/****************************************************************************** * * Name: skxmac2.c * Project: Gigabit Ethernet Adapters, Common Modules * Version: $Revision: 2.56 $ * Date: $Date: 2006/04/27 07:50:32 $ * Purpose: Contains functions to initialize the MACs and PHYs * ******************************************************************************/ /****************************************************************************** * * LICENSE: * (C)Copyright 1998-2002 SysKonnect. * (C)Copyright 2002-2006 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 * ******************************************************************************/ #include #ifdef CONFIG_SK98 #include "h/skdrv1st.h" #include "h/skdrv2nd.h" /* typedefs *******************************************************************/ /* BCOM PHY magic pattern list */ typedef struct s_PhyHack { int PhyReg; /* PHY register */ SK_U16 PhyVal; /* Value to write */ } BCOM_HACK; /* local variables ************************************************************/ #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) static const char SysKonnectFileId[] = "@(#) $Id: skxmac2.c,v 2.56 2006/04/27 07:50:32 malthoff Exp $ (C) Marvell."; #endif #ifdef GENESIS BCOM_HACK BcomRegA1Hack[] = { { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, { 0, 0 } }; BCOM_HACK BcomRegC0Hack[] = { { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, { 0, 0 } }; #endif /* function prototypes ********************************************************/ #ifdef GENESIS static void SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL); static void SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL); static int SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int); static int SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int); #endif /* GENESIS */ #ifdef YUKON static void SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL); static int SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int); #endif /* YUKON */ #ifdef OTHER_PHY static void SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL); static void SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL); static int SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int); static int SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int); #endif /* OTHER_PHY */ #ifdef GENESIS /****************************************************************************** * * SkXmPhyRead() - Read from XMAC PHY register * * Description: reads a 16-bit word from XMAC PHY or ext. PHY * * Returns: * nothing */ int SkXmPhyRead( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 SK_FAR *pVal) /* Pointer to Value */ { SK_U16 Mmu; SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; /* write the PHY register's address */ XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr); /* get the PHY register's value */ XM_IN16(IoC, Port, XM_PHY_DATA, pVal); if (pPrt->PhyType != SK_PHY_XMAC) { do { XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); /* wait until 'Ready' is set */ } while ((Mmu & XM_MMU_PHY_RDY) == 0); /* get the PHY register's value */ XM_IN16(IoC, Port, XM_PHY_DATA, pVal); } return(0); } /* SkXmPhyRead */ /****************************************************************************** * * SkXmPhyWrite() - Write to XMAC PHY register * * Description: writes a 16-bit word to XMAC PHY or ext. PHY * * Returns: * nothing */ int SkXmPhyWrite( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 Val) /* Value */ { SK_U16 Mmu; SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PhyType != SK_PHY_XMAC) { do { XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); /* wait until 'Busy' is cleared */ } while ((Mmu & XM_MMU_PHY_BUSY) != 0); } /* write the PHY register's address */ XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr); /* write the PHY register's value */ XM_OUT16(IoC, Port, XM_PHY_DATA, Val); if (pPrt->PhyType != SK_PHY_XMAC) { do { XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); /* wait until 'Busy' is cleared */ } while ((Mmu & XM_MMU_PHY_BUSY) != 0); } return(0); } /* SkXmPhyWrite */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmPhyRead() - Read from GPHY register * * Description: reads a 16-bit word from GPHY through MDIO * * Returns: * 0 o.k. * 1 error during MDIO read * 2 timeout */ int SkGmPhyRead( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 SK_FAR *pVal) /* Pointer to Value */ { SK_U16 Word; SK_U16 Ctrl; SK_GEPORT *pPrt; SK_U32 StartTime; SK_U32 CurrTime; SK_U32 Delta; SK_U32 TimeOut; int Rtv; Rtv = 0; *pVal = 0xffff; pPrt = &pAC->GIni.GP[Port]; /* set PHY-Register offset and 'Read' OpCode (= 1) */ Word = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD); GM_OUT16(IoC, Port, GM_SMI_CTRL, Word); /* additional check for MDC/MDIO activity */ GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); if (Ctrl == 0xffff || (Ctrl & GM_SMI_CT_OP_RD) == 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("PHY read impossible on Port %d (Ctrl=0x%04x)\n", Port, Ctrl)); return(1); } Word |= GM_SMI_CT_BUSY; SK_IN32(IoC, GMAC_TI_ST_VAL, &StartTime); /* set timeout to 10 ms */ TimeOut = HW_MS_TO_TICKS(pAC, 10); do { /* wait until 'Busy' is cleared and 'ReadValid' is set */ #ifdef VCPU VCPUwaitTime(1000); #endif /* VCPU */ SK_IN32(IoC, GMAC_TI_ST_VAL, &CurrTime); if (CurrTime >= StartTime) { Delta = CurrTime - StartTime; } else { Delta = CurrTime + ~StartTime + 1; } if (Delta > TimeOut) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("PHY read timeout on Port %d (Ctrl=0x%04x)\n", Port, Ctrl)); Rtv = 2; break; } GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); /* Error on reading SMI Control Register */ if (Ctrl == 0xffff) { return(1); } } while ((Ctrl ^ Word) != (GM_SMI_CT_RD_VAL | GM_SMI_CT_BUSY)); GM_IN16(IoC, Port, GM_SMI_DATA, pVal); /* dummy read after GM_IN16() */ SK_IN32(IoC, GMAC_TI_ST_VAL, &CurrTime); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("SkGmPhyRead Port:%d, Reg=%d, Val = 0x%04X\n", Port, PhyReg, *pVal)); return(Rtv); } /* SkGmPhyRead */ /****************************************************************************** * * SkGmPhyWrite() - Write to GPHY register * * Description: writes a 16-bit word to GPHY through MDIO * * Returns: * 0 o.k. * 1 error during MDIO read * 2 timeout */ int SkGmPhyWrite( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 Val) /* Value */ { SK_U16 Ctrl; SK_GEPORT *pPrt; SK_U32 StartTime; SK_U32 CurrTime; SK_U32 Delta; SK_U32 TimeOut; SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("SkGmPhyWrite Port:%d, Reg=%d, Val = 0x%04X\n", Port, PhyReg, Val)); pPrt = &pAC->GIni.GP[Port]; /* write the PHY register's value */ GM_OUT16(IoC, Port, GM_SMI_DATA, Val); #ifdef DEBUG /* additional check for MDC/MDIO activity */ GM_IN16(IoC, Port, GM_SMI_DATA, &Ctrl); if (Ctrl != Val) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("PHY write impossible on Port %d (Val=0x%04x)\n", Port, Ctrl)); return(1); } #endif /* DEBUG */ /* set PHY-Register offset and 'Write' OpCode (= 0) */ Ctrl = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg)); GM_OUT16(IoC, Port, GM_SMI_CTRL, Ctrl); SK_IN32(IoC, GMAC_TI_ST_VAL, &StartTime); /* set timeout to 10 ms */ TimeOut = HW_MS_TO_TICKS(pAC, 10); do { /* wait until 'Busy' is cleared */ #ifdef VCPU VCPUwaitTime(1000); #endif /* VCPU */ SK_IN32(IoC, GMAC_TI_ST_VAL, &CurrTime); if (CurrTime >= StartTime) { Delta = CurrTime - StartTime; } else { Delta = CurrTime + ~StartTime + 1; } if (Delta > TimeOut) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("PHY write timeout on Port %d (Ctrl=0x%04x)\n", Port, Ctrl)); return(2); } GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); /* Error on reading SMI Control Register */ if (Ctrl == 0xffff) { return(1); } } while ((Ctrl & GM_SMI_CT_BUSY) != 0); /* dummy read after GM_IN16() */ SK_IN32(IoC, GMAC_TI_ST_VAL, &CurrTime); return(0); } /* SkGmPhyWrite */ #endif /* YUKON */ #ifdef SK_DIAG /****************************************************************************** * * SkGePhyRead() - Read from PHY register * * Description: calls a read PHY routine dep. on board type * * Returns: * nothing */ void SkGePhyRead( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 *pVal) /* Pointer to Value */ { pAC->GIni.GIFunc.pFnMacPhyRead(pAC, IoC, Port, PhyReg, pVal); } /* SkGePhyRead */ /****************************************************************************** * * SkGePhyWrite() - Write to PHY register * * Description: calls a write PHY routine dep. on board type * * Returns: * nothing */ void SkGePhyWrite( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int PhyReg, /* Register Address (Offset) */ SK_U16 Val) /* Value */ { pAC->GIni.GIFunc.pFnMacPhyWrite(pAC, IoC, Port, PhyReg, Val); } /* SkGePhyWrite */ #endif /* SK_DIAG */ /****************************************************************************** * * SkMacPromiscMode() - Enable / Disable Promiscuous Mode * * Description: * enables / disables promiscuous mode by setting Mode Register (XMAC) or * Receive Control Register (GMAC) dep. on board type * * Returns: * nothing */ void SkMacPromiscMode( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL Enable) /* Enable / Disable */ { #ifdef YUKON SK_U16 RcReg; #endif #ifdef GENESIS SK_U32 MdReg; #endif #ifdef GENESIS if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); /* enable or disable promiscuous mode */ if (Enable) { MdReg |= XM_MD_ENA_PROM; } else { MdReg &= ~XM_MD_ENA_PROM; } /* setup Mode Register */ XM_OUT32(IoC, Port, XM_MODE, MdReg); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg); /* enable or disable unicast and multicast filtering */ if (Enable) { RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } else { RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } /* setup Receive Control Register */ GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg); } #endif /* YUKON */ } /* SkMacPromiscMode*/ /****************************************************************************** * * SkMacHashing() - Enable / Disable Hashing * * Description: * enables / disables hashing by setting Mode Register (XMAC) or * Receive Control Register (GMAC) dep. on board type * * Returns: * nothing */ void SkMacHashing( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL Enable) /* Enable / Disable */ { #ifdef YUKON SK_U16 RcReg; #endif #ifdef GENESIS SK_U32 MdReg; #endif #ifdef GENESIS if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); /* enable or disable hashing */ if (Enable) { MdReg |= XM_MD_ENA_HASH; } else { MdReg &= ~XM_MD_ENA_HASH; } /* setup Mode Register */ XM_OUT32(IoC, Port, XM_MODE, MdReg); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg); /* enable or disable multicast filtering */ if (Enable) { RcReg |= GM_RXCR_MCF_ENA; } else { RcReg &= ~GM_RXCR_MCF_ENA; } /* setup Receive Control Register */ GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg); } #endif /* YUKON */ } /* SkMacHashing*/ #ifdef SK_DIAG /****************************************************************************** * * SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register * * Description: * The features * - FCS stripping, SK_STRIP_FCS_ON/OFF * - pad byte stripping, SK_STRIP_PAD_ON/OFF * - don't set XMR_FS_ERR in status SK_LENERR_OK_ON/OFF * for inrange length error frames * - don't set XMR_FS_ERR in status SK_BIG_PK_OK_ON/OFF * for frames > 1514 bytes * - enable Rx of own packets SK_SELF_RX_ON/OFF * * for incoming packets may be enabled/disabled by this function. * Additional modes may be added later. * Multiple modes can be enabled/disabled at the same time. * The new configuration is written to the Rx Command register immediately. * * Returns: * nothing */ static void SkXmSetRxCmd( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ { SK_U16 OldRxCmd; SK_U16 RxCmd; XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd); RxCmd = OldRxCmd; switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) { case SK_STRIP_FCS_ON: RxCmd |= XM_RX_STRIP_FCS; break; case SK_STRIP_FCS_OFF: RxCmd &= ~XM_RX_STRIP_FCS; break; } switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) { case SK_STRIP_PAD_ON: RxCmd |= XM_RX_STRIP_PAD; break; case SK_STRIP_PAD_OFF: RxCmd &= ~XM_RX_STRIP_PAD; break; } switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) { case SK_LENERR_OK_ON: RxCmd |= XM_RX_LENERR_OK; break; case SK_LENERR_OK_OFF: RxCmd &= ~XM_RX_LENERR_OK; break; } switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) { case SK_BIG_PK_OK_ON: RxCmd |= XM_RX_BIG_PK_OK; break; case SK_BIG_PK_OK_OFF: RxCmd &= ~XM_RX_BIG_PK_OK; break; } switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) { case SK_SELF_RX_ON: RxCmd |= XM_RX_SELF_RX; break; case SK_SELF_RX_OFF: RxCmd &= ~XM_RX_SELF_RX; break; } /* Write the new mode to the Rx command register if required */ if (OldRxCmd != RxCmd) { XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd); } } /* SkXmSetRxCmd */ /****************************************************************************** * * SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register * * Description: * The features * - FCS (CRC) stripping, SK_STRIP_FCS_ON/OFF * - don't set GMR_FS_LONG_ERR SK_BIG_PK_OK_ON/OFF * for frames > 1514 bytes * - enable Rx of own packets SK_SELF_RX_ON/OFF * * for incoming packets may be enabled/disabled by this function. * Additional modes may be added later. * Multiple modes can be enabled/disabled at the same time. * The new configuration is written to the Rx Command register immediately. * * Returns: * nothing */ static void SkGmSetRxCmd( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ { SK_U16 RxCmd; if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) { GM_IN16(IoC, Port, GM_RX_CTRL, &RxCmd); if ((Mode & SK_STRIP_FCS_ON) != 0) { RxCmd |= GM_RXCR_CRC_DIS; } else { RxCmd &= ~GM_RXCR_CRC_DIS; } /* Write the new mode to the Rx Control register */ GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd); } if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) { GM_IN16(IoC, Port, GM_SERIAL_MODE, &RxCmd); if ((Mode & SK_BIG_PK_OK_ON) != 0) { RxCmd |= GM_SMOD_JUMBO_ENA; } else { RxCmd &= ~GM_SMOD_JUMBO_ENA; } /* Write the new mode to the Serial Mode register */ GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd); } } /* SkGmSetRxCmd */ /****************************************************************************** * * SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register * * Description: modifies the MAC's Rx Control reg. dep. on board type * * Returns: * nothing */ void SkMacSetRxCmd( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Mode) /* Rx Mode */ { if (pAC->GIni.GIGenesis) { SkXmSetRxCmd(pAC, IoC, Port, Mode); } else { SkGmSetRxCmd(pAC, IoC, Port, Mode); } } /* SkMacSetRxCmd */ /****************************************************************************** * * SkMacCrcGener() - Enable / Disable CRC Generation * * Description: enables / disables CRC generation dep. on board type * * Returns: * nothing */ void SkMacCrcGener( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL Enable) /* Enable / Disable */ { SK_U16 Word; if (pAC->GIni.GIGenesis) { XM_IN16(IoC, Port, XM_TX_CMD, &Word); if (Enable) { Word &= ~XM_TX_NO_CRC; } else { Word |= XM_TX_NO_CRC; } /* setup Tx Command Register */ XM_OUT16(IoC, Port, XM_TX_CMD, Word); } else { GM_IN16(IoC, Port, GM_TX_CTRL, &Word); if (Enable) { Word &= ~GM_TXCR_CRC_DIS; } else { Word |= GM_TXCR_CRC_DIS; } /* setup Tx Control Register */ GM_OUT16(IoC, Port, GM_TX_CTRL, Word); } } /* SkMacCrcGener*/ #endif /* SK_DIAG */ #ifdef GENESIS /****************************************************************************** * * SkXmClrExactAddr() - Clear Exact Match Address Registers * * Description: * All Exact Match Address registers of the XMAC 'Port' will be * cleared starting with 'StartNum' up to (and including) the * Exact Match address number of 'StopNum'. * * Returns: * nothing */ void SkXmClrExactAddr( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int StartNum, /* Begin with this Address Register Index (0..15) */ int StopNum) /* Stop after finished with this Register Idx (0..15) */ { int i; SK_U16 ZeroAddr[3] = {0, 0, 0}; if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 || StartNum > StopNum) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG); return; } for (i = StartNum; i <= StopNum; i++) { XM_OUTADDR(IoC, Port, XM_EXM(i), ZeroAddr); } } /* SkXmClrExactAddr */ #endif /* GENESIS */ /****************************************************************************** * * SkMacFlushTxFifo() - Flush the MAC's transmit FIFO * * Description: * Flush the transmit FIFO of the MAC specified by the index 'Port' * * Returns: * nothing */ void SkMacFlushTxFifo( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { #ifdef GENESIS SK_U32 MdReg; if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { /* no way to flush the FIFO we have to issue a reset */ /* TBD */ } #endif /* YUKON */ } /* SkMacFlushTxFifo */ /****************************************************************************** * * SkMacFlushRxFifo() - Flush the MAC's receive FIFO * * Description: * Flush the receive FIFO of the MAC specified by the index 'Port' * * Returns: * nothing */ void SkMacFlushRxFifo( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { #ifdef GENESIS SK_U32 MdReg; if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { /* no way to flush the FIFO we have to issue a reset */ /* TBD */ } #endif /* YUKON */ } /* SkMacFlushRxFifo */ #ifdef GENESIS /****************************************************************************** * * SkXmSoftRst() - Do a XMAC software reset * * Description: * The PHY registers should not be destroyed during this * kind of software reset. Therefore the XMAC Software Reset * (XM_GP_RES_MAC bit in XM_GP_PORT) must not be used! * * The software reset is done by * - disabling the Rx and Tx state machine, * - resetting the statistics module, * - clear all other significant XMAC Mode, * Command, and Control Registers * - clearing the Hash Register and the * Exact Match Address registers, and * - flushing the XMAC's Rx and Tx FIFOs. * * Note: * Another requirement when stopping the XMAC is to * avoid sending corrupted frames on the network. * Disabling the Tx state machine will NOT interrupt * the currently transmitted frame. But we must take care * that the Tx FIFO is cleared AFTER the current frame * is complete sent to the network. * * It takes about 12ns to send a frame with 1538 bytes. * One PCI clock goes at least 15ns (66MHz). Therefore * after reading XM_GP_PORT back, we are sure that the * transmitter is disabled AND idle. And this means * we may flush the transmit FIFO now. * * Returns: * nothing */ static void SkXmSoftRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U16 ZeroAddr[4] = {0, 0, 0, 0}; /* reset the statistics module */ XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT); /* disable all XMAC IRQs */ XM_OUT16(IoC, Port, XM_IMSK, 0xffff); XM_OUT32(IoC, Port, XM_MODE, 0); /* clear Mode Reg */ XM_OUT16(IoC, Port, XM_TX_CMD, 0); /* reset TX CMD Reg */ XM_OUT16(IoC, Port, XM_RX_CMD, 0); /* reset RX CMD Reg */ /* disable all PHY IRQs */ switch (pAC->GIni.GP[Port].PhyType) { case SK_PHY_BCOM: SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff); break; #ifdef OTHER_PHY case SK_PHY_LONE: SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0); break; case SK_PHY_NAT: /* todo: National SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */ break; #endif /* OTHER_PHY */ } /* clear the Hash Register */ XM_OUTHASH(IoC, Port, XM_HSM, ZeroAddr); /* clear the Exact Match Address registers */ SkXmClrExactAddr(pAC, IoC, Port, 0, 15); /* clear the Source Check Address registers */ XM_OUTHASH(IoC, Port, XM_SRC_CHK, ZeroAddr); } /* SkXmSoftRst */ /****************************************************************************** * * SkXmHardRst() - Do a XMAC hardware reset * * Description: * The XMAC of the specified 'Port' and all connected devices * (PHY and SERDES) will receive a reset signal on its *Reset pins. * External PHYs must be reset by clearing a bit in the GPIO register * (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns). * * ATTENTION: * It is absolutely necessary to reset the SW_RST Bit first * before calling this function. * * Returns: * nothing */ static void SkXmHardRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U32 Reg; int i; int TOut; SK_U16 Word; for (i = 0; i < 4; i++) { /* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); TOut = 0; do { if (TOut++ > 10000) { /* * Adapter seems to be in RESET state. * Registers cannot be written. */ return; } SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST); SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word); } while ((Word & MFF_SET_MAC_RST) == 0); } /* For external PHYs there must be special handling */ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { SK_IN32(IoC, B2_GP_IO, &Reg); if (Port == 0) { Reg |= GP_DIR_0; /* set to output */ Reg &= ~GP_IO_0; /* set PHY reset (active low) */ } else { Reg |= GP_DIR_2; /* set to output */ Reg &= ~GP_IO_2; /* set PHY reset (active low) */ } /* reset external PHY */ SK_OUT32(IoC, B2_GP_IO, Reg); /* short delay */ SK_IN32(IoC, B2_GP_IO, &Reg); } } /* SkXmHardRst */ /****************************************************************************** * * SkXmClearRst() - Release the PHY & XMAC reset * * Description: * * Returns: * nothing */ static void SkXmClearRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U32 DWord; /* clear HW reset */ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { SK_IN32(IoC, B2_GP_IO, &DWord); if (Port == 0) { DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */ } else { DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */ } /* Clear PHY reset */ SK_OUT32(IoC, B2_GP_IO, DWord); /* enable GMII interface */ XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); } } /* SkXmClearRst */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmSoftRst() - Do a GMAC software reset * * Description: * The GPHY registers should not be destroyed during this * kind of software reset. * * Returns: * nothing */ static void SkGmSoftRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U16 EmptyHash[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; SK_U16 RxCtrl; /* reset the statistics module */ /* disable all GMAC IRQs */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_IRQ_MSK), 0); /* disable all PHY IRQs */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0); /* clear the Hash Register */ GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash); /* enable Unicast and Multicast filtering */ GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl); GM_OUT16(IoC, Port, GM_RX_CTRL, RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } /* SkGmSoftRst */ /****************************************************************************** * * SkGmHardRst() - Do a GMAC hardware reset * * Description: * * Returns: * nothing */ static void SkGmHardRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U32 DWord; /* WA code for COMA mode */ if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { SK_IN32(IoC, B2_GP_IO, &DWord); DWord |= (GP_DIR_9 | GP_IO_9); /* set PHY reset */ SK_OUT32(IoC, B2_GP_IO, DWord); } /* set GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_SET); /* set GMAC Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_RST_SET); } /* SkGmHardRst */ /****************************************************************************** * * SkGmClearRst() - Release the GPHY & GMAC reset * * Description: * * Returns: * nothing */ static void SkGmClearRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U32 DWord; #ifdef SK_DIAG SK_U16 PhyId0; SK_U16 PhyId1; #endif /* SK_DIAG */ #if defined(SK_DIAG) || defined(DEBUG) SK_U16 Word; #endif /* SK_DIAG || DEBUG */ /* WA code for COMA mode */ if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { SK_IN32(IoC, B2_GP_IO, &DWord); DWord |= GP_DIR_9; /* set to output */ DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ /* clear PHY reset */ SK_OUT32(IoC, B2_GP_IO, DWord); } #ifdef VCPU /* set MAC Reset before PHY reset is set */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_RST_SET); #endif /* VCPU */ if (CHIP_ID_YUKON_2(pAC)) { /* set GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_SET); /* release GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_CLR); #ifdef DEBUG /* additional check for PEX */ SK_IN16(IoC, GPHY_CTRL, &Word); if (pAC->GIni.GIPciBus == SK_PEX_BUS && Word != GPC_RST_CLR) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("Error on PEX-bus after GPHY reset\n")); } #endif /* DEBUG */ } else { /* set HWCFG_MODE */ DWord = GPC_INT_POL | GPC_DIS_FC | GPC_DIS_SLEEP | GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB); /* set GPHY Control reset */ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); /* release GPHY Control reset */ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); } #ifdef VCPU /* wait for internal initialization of GPHY */ VCPUprintf(0, "Waiting until PHY %d is ready to initialize\n", Port); VCpuWait(10000); /* release GMAC reset */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_RST_CLR); /* wait for stable GMAC clock */ VCpuWait(9000); #endif /* VCPU */ /* clear GMAC Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_RST_CLR); #ifdef SK_DIAG if (HW_FEATURE(pAC, HWF_WA_DEV_472) && Port == MAC_2) { /* clear GMAC 1 Control reset */ SK_OUT8(IoC, MR_ADDR(MAC_1, GMAC_CTRL), (SK_U8)GMC_RST_CLR); do { /* set GMAC 2 Control reset */ SK_OUT8(IoC, MR_ADDR(MAC_2, GMAC_CTRL), (SK_U8)GMC_RST_SET); /* clear GMAC 2 Control reset */ SK_OUT8(IoC, MR_ADDR(MAC_2, GMAC_CTRL), (SK_U8)GMC_RST_CLR); SkGmPhyRead(pAC, IoC, MAC_2, PHY_MARV_ID0, &PhyId0); SkGmPhyRead(pAC, IoC, MAC_2, PHY_MARV_ID1, &PhyId1); SkGmPhyRead(pAC, IoC, MAC_2, PHY_MARV_INT_MASK, &Word); } while (Word != 0 || PhyId0 != PHY_MARV_ID0_VAL || PhyId1 != PHY_MARV_ID1_Y2); } #endif /* SK_DIAG */ #ifdef VCPU VCpuWait(2000); SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord); SK_IN32(IoC, B0_ISRC, &DWord); #endif /* VCPU */ } /* SkGmClearRst */ #endif /* YUKON */ /****************************************************************************** * * SkMacSoftRst() - Do a MAC software reset * * Description: calls a MAC software reset routine dep. on board type * * Returns: * nothing */ void SkMacSoftRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { /* disable receiver and transmitter */ SkMacRxTxDisable(pAC, IoC, Port); #ifdef GENESIS if (pAC->GIni.GIGenesis) { SkXmSoftRst(pAC, IoC, Port); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { SkGmSoftRst(pAC, IoC, Port); } #endif /* YUKON */ /* flush the MAC's Rx and Tx FIFOs */ SkMacFlushTxFifo(pAC, IoC, Port); SkMacFlushRxFifo(pAC, IoC, Port); pAC->GIni.GP[Port].PState = SK_PRT_STOP; } /* SkMacSoftRst */ /****************************************************************************** * * SkMacHardRst() - Do a MAC hardware reset * * Description: calls a MAC hardware reset routine dep. on board type * * Returns: * nothing */ void SkMacHardRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { #ifdef GENESIS if (pAC->GIni.GIGenesis) { SkXmHardRst(pAC, IoC, Port); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { SkGmHardRst(pAC, IoC, Port); } #endif /* YUKON */ pAC->GIni.GP[Port].PHWLinkUp = SK_FALSE; pAC->GIni.GP[Port].PState = SK_PRT_RESET; } /* SkMacHardRst */ #ifndef SK_SLIM /****************************************************************************** * * SkMacClearRst() - Clear the MAC reset * * Description: calls a clear MAC reset routine dep. on board type * * Returns: * nothing */ void SkMacClearRst( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { #ifdef GENESIS if (pAC->GIni.GIGenesis) { SkXmClearRst(pAC, IoC, Port); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { SkGmClearRst(pAC, IoC, Port); } #endif /* YUKON */ } /* SkMacClearRst */ #endif /* !SK_SLIM */ #ifdef GENESIS /****************************************************************************** * * SkXmInitMac() - Initialize the XMAC II * * Description: * Initialize the XMAC of the specified port. * The XMAC must be reset or stopped before calling this function. * * Note: * The XMAC's Rx and Tx state machine is still disabled when returning. * * Returns: * nothing */ void SkXmInitMac( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; int i; SK_U16 SWord; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PState == SK_PRT_STOP) { /* Verify that the reset bit is cleared */ SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); if ((SWord & MFF_SET_MAC_RST) != 0) { /* PState does not match HW state */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, ("SkXmInitMac: PState does not match HW state")); /* Correct it */ pPrt->PState = SK_PRT_RESET; } } if (pPrt->PState == SK_PRT_RESET) { SkXmClearRst(pAC, IoC, Port); if (pPrt->PhyType != SK_PHY_XMAC) { /* read Id from external PHY (all have the same address) */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1); /* * Optimize MDIO transfer by suppressing preamble. * Must be done AFTER first access to BCOM chip. */ XM_IN16(IoC, Port, XM_MMU_CMD, &SWord); XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE); if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) { /* * Workaround BCOM Errata for the C0 type. * Write magic patterns to reserved registers. */ i = 0; while (BcomRegC0Hack[i].PhyReg != 0) { SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg, BcomRegC0Hack[i].PhyVal); i++; } } else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) { /* * Workaround BCOM Errata for the A1 type. * Write magic patterns to reserved registers. */ i = 0; while (BcomRegA1Hack[i].PhyReg != 0) { SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg, BcomRegA1Hack[i].PhyVal); i++; } } /* * Workaround BCOM Errata (#10523) for all BCom PHYs. * Disable Power Management after reset. */ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord); SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, (SK_U16)(SWord | PHY_B_AC_DIS_PM)); /* PHY LED initialization is done in SkGeXmitLED() */ } /* Dummy read the Interrupt source register */ XM_IN16(IoC, Port, XM_ISRC, &SWord); /* * The auto-negotiation process starts immediately after * clearing the reset. The auto-negotiation process should be * started by the SIRQ, therefore stop it here immediately. */ SkMacInitPhy(pAC, IoC, Port, SK_FALSE); } /* * configure the XMACs Station Address * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B */ for (i = 0; i < 3; i++) { /* * The following 2 statements are together endianess * independent. Remember this when changing. */ SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord); XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord); } /* Tx Inter Packet Gap (XM_TX_IPG): use default */ /* Tx High Water Mark (XM_TX_HI_WM): use default */ /* Tx Low Water Mark (XM_TX_LO_WM): use default */ /* Host Request Threshold (XM_HT_THR): use default */ /* Rx Request Threshold (XM_RX_THR): use default */ /* Rx Low Water Mark (XM_RX_LO_WM): use default */ /* configure Rx High Water Mark (XM_RX_HI_WM) */ XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM); /* Configure Tx Request Threshold */ SWord = SK_XM_THR_SL; /* for single port */ if (pAC->GIni.GIMacsFound > 1) { switch (pPrt->PPortUsage) { case SK_RED_LINK: SWord = SK_XM_THR_REDL; /* redundant link */ break; case SK_MUL_LINK: SWord = SK_XM_THR_MULL; /* load balancing */ break; case SK_JUMBO_LINK: SWord = SK_XM_THR_JUMBO; /* jumbo frames */ break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG); break; } } XM_OUT16(IoC, Port, XM_TX_THR, SWord); /* setup register defaults for the Tx Command Register */ XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD); /* setup register defaults for the Rx Command Register */ SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK; if (pPrt->PPortUsage == SK_JUMBO_LINK) { SWord |= XM_RX_BIG_PK_OK; } if (pPrt->PLinkMode == SK_LMODE_HALF) { /* * If in manual half duplex mode the other side might be in * full duplex mode, so ignore if a carrier extension is not seen * on frames received */ SWord |= XM_RX_DIS_CEXT; } XM_OUT16(IoC, Port, XM_RX_CMD, SWord); /* * setup register defaults for the Mode Register * - Don't strip error frames to avoid Store & Forward * on the Rx side. * - Enable 'Check Station Address' bit * - Enable 'Check Address Array' bit */ XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE); /* * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK) * - Enable all bits excepting 'Octets Rx OK Low CntOv' * and 'Octets Rx OK Hi Cnt Ov'. */ XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK); /* * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK) * - Enable all bits excepting 'Octets Tx OK Low CntOv' * and 'Octets Tx OK Hi Cnt Ov'. */ XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK); /* * Do NOT init XMAC interrupt mask here. * All interrupts remain disable until link comes up! */ /* * Any additional configuration changes may be done now. * The last action is to enable the Rx and Tx state machine. * This should be done after the auto-negotiation process * has been completed successfully. */ } /* SkXmInitMac */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmInitMac() - Initialize the GMAC * * Description: * Initialize the GMAC of the specified port. * The GMAC must be reset or stopped before calling this function. * * Note: * The GMAC's Rx and Tx state machine is still disabled when returning. * * Returns: * nothing */ void SkGmInitMac( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; int i; SK_U16 SWord; SK_U32 DWord; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PState == SK_PRT_STOP) { /* Verify that the reset bit is cleared */ SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord); if ((DWord & GMC_RST_SET) != 0) { /* PState does not match HW state */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("SkGmInitMac: PState does not match HW state")); /* Correct it */ pPrt->PState = SK_PRT_RESET; } else { /* enable PHY interrupts */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, (SK_U16)PHY_M_DEF_MSK); } } if (pPrt->PState == SK_PRT_RESET) { SkGmHardRst(pAC, IoC, Port); SkGmClearRst(pAC, IoC, Port); #ifndef SK_SLIM if (HW_FEATURE(pAC, HWF_FORCE_AUTO_NEG) && pPrt->PLinkModeConf < SK_LMODE_AUTOHALF) { /* Force Auto-Negotiation */ pPrt->PLinkMode = (pPrt->PLinkModeConf == SK_LMODE_FULL) ? SK_LMODE_AUTOBOTH : SK_LMODE_AUTOHALF; } #endif /* !SK_SLIM */ /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* Auto-negotiation disabled */ /* get General Purpose Control */ GM_IN16(IoC, Port, GM_GP_CTRL, &SWord); /* disable auto-update for speed, duplex and flow-control */ SWord |= GM_GPCR_AU_ALL_DIS; /* setup General Purpose Control Register */ GM_OUT16(IoC, Port, GM_GP_CTRL, SWord); SWord = GM_GPCR_AU_ALL_DIS; } else { SWord = 0; } /* speed settings */ switch (pPrt->PLinkSpeed) { case SK_LSPEED_AUTO: case SK_LSPEED_1000MBPS: if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) { SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100; } break; case SK_LSPEED_100MBPS: SWord |= GM_GPCR_SPEED_100; break; case SK_LSPEED_10MBPS: break; } /* duplex settings */ if (pPrt->PLinkMode != SK_LMODE_HALF) { /* set full duplex */ SWord |= GM_GPCR_DUP_FULL; } /* flow-control settings */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* disable Tx & Rx flow-control */ SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; break; case SK_FLOW_MODE_LOC_SEND: /* disable Rx flow-control */ SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; break; case SK_FLOW_MODE_SYMMETRIC: case SK_FLOW_MODE_SYM_OR_REM: /* enable Tx & Rx flow-control */ break; } /* setup General Purpose Control Register */ GM_OUT16(IoC, Port, GM_GP_CTRL, SWord); /* dummy read the Interrupt Source Register */ SK_IN16(IoC, MR_ADDR(Port, GMAC_IRQ_SRC), &SWord); #ifndef VCPU SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); #endif /* !VCPU */ } (void)SkGmResetCounter(pAC, IoC, Port); /* setup Transmit Control Register */ GM_OUT16(IoC, Port, GM_TX_CTRL, (SK_U16)TX_COL_THR(pPrt->PMacColThres)); /* setup Receive Control Register */ SWord = GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA | GM_RXCR_CRC_DIS; GM_OUT16(IoC, Port, GM_RX_CTRL, SWord); /* setup Transmit Flow Control Register */ GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff); /* setup Transmit Parameter Register */ #ifdef VCPU GM_IN16(IoC, Port, GM_TX_PARAM, &SWord); #endif /* VCPU */ SWord = (SK_U16)(TX_JAM_LEN_VAL(pPrt->PMacJamLen) | TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) | TX_IPG_JAM_DATA(pPrt->PMacJamIpgData) | TX_BACK_OFF_LIM(pPrt->PMacBackOffLim)); GM_OUT16(IoC, Port, GM_TX_PARAM, SWord); /* configure the Serial Mode Register */ SWord = (SK_U16)(DATA_BLIND_VAL(pPrt->PMacDataBlind) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData)); if (pPrt->PMacLimit4) { /* reset of collision counter after 4 consecutive collisions */ SWord |= GM_SMOD_LIMIT_4; } if (pPrt->PPortUsage == SK_JUMBO_LINK) { /* enable jumbo mode (Max. Frame Length = 9018) */ SWord |= GM_SMOD_JUMBO_ENA; } GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord); /* * configure the GMACs Station Addresses * in PROM you can find our addresses at: * B2_MAC_1 = xx xx xx xx xx x0 virtual address * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort */ for (i = 0; i < 3; i++) { /* * The following 2 statements are together endianess * independent. Remember this when changing. */ /* physical address: will be used for pause frames */ SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord); #ifdef WA_DEV_16 /* WA for deviation #16 */ if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) { /* swap the address bytes */ SWord = ((SWord & 0xff00) >> 8) | ((SWord & 0x00ff) << 8); /* write to register in reversed order */ GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord); } else { GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord); } #else GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord); #endif /* WA_DEV_16 */ /* virtual address: will be used for data */ SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord); GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord); /* reset Multicast filtering Hash registers 1-3 */ GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + i * 4, 0); } /* reset Multicast filtering Hash register 4 */ GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0); /* enable interrupt mask for counter overflows */ GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0); GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0); GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0); } /* SkGmInitMac */ #endif /* YUKON */ #ifdef GENESIS /****************************************************************************** * * SkXmInitDupMd() - Initialize the XMACs Duplex Mode * * Description: * This function initializes the XMACs Duplex Mode. * It should be called after successfully finishing * the Auto-negotiation Process * * Returns: * nothing */ void SkXmInitDupMd( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { switch (pAC->GIni.GP[Port].PLinkModeStatus) { case SK_LMODE_STAT_AUTOHALF: case SK_LMODE_STAT_HALF: /* Configuration Actions for Half Duplex Mode */ /* * XM_BURST = default value. We are probable not quick * enough at the 'XMAC' bus to burst 8kB. * The XMAC stops bursting if no transmit frames * are available or the burst limit is exceeded. */ /* XM_TX_RT_LIM = default value (15) */ /* XM_TX_STIME = default value (0xff = 4096 bit times) */ break; case SK_LMODE_STAT_AUTOFULL: case SK_LMODE_STAT_FULL: /* Configuration Actions for Full Duplex Mode */ /* * The duplex mode is configured by the PHY, * therefore it seems to be that there is nothing * to do here. */ break; case SK_LMODE_STAT_UNKNOWN: default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG); break; } } /* SkXmInitDupMd */ /****************************************************************************** * * SkXmInitPauseMd() - initialize the Pause Mode to be used for this port * * Description: * This function initializes the Pause Mode which should * be used for this port. * It should be called after successfully finishing * the Auto-negotiation Process * * Returns: * nothing */ void SkXmInitPauseMd( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U32 DWord; SK_U16 Word; pPrt = &pAC->GIni.GP[Port]; XM_IN16(IoC, Port, XM_MMU_CMD, &Word); if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE || pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) { /* disable Pause Frame Reception */ Word |= XM_MMU_IGN_PF; } else { /* * enabling pause frame reception is required for 1000BT * because the XMAC is not reset if the link is going down */ /* enable Pause Frame Reception */ Word &= ~XM_MMU_IGN_PF; } XM_OUT16(IoC, Port, XM_MMU_CMD, Word); XM_IN32(IoC, Port, XM_MODE, &DWord); if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC || pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) { /* * Configure Pause Frame Generation * Use internal and external Pause Frame Generation. * Sending pause frames is edge triggered. * Send a Pause frame with the maximum pause time if * internal oder external FIFO full condition occurs. * Send a zero pause time frame to re-start transmission. */ /* XM_PAUSE_DA = '010000C28001' (default) */ /* XM_MAC_PTIME = 0xffff (maximum) */ /* remember this value is defined in big endian (!) */ XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff); /* set Pause Mode in Mode Register */ DWord |= XM_PAUSE_MODE; /* set Pause Mode in MAC Rx FIFO */ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE); } else { /* * disable pause frame generation is required for 1000BT * because the XMAC is not reset if the link is going down */ /* disable Pause Mode in Mode Register */ DWord &= ~XM_PAUSE_MODE; /* disable Pause Mode in MAC Rx FIFO */ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE); } XM_OUT32(IoC, Port, XM_MODE, DWord); } /* SkXmInitPauseMd*/ /****************************************************************************** * * SkXmInitPhyXmac() - Initialize the XMAC PHY registers * * Description: initializes all the XMACs PHY registers * * Note: * * Returns: * nothing */ static void SkXmInitPhyXmac( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { SK_GEPORT *pPrt; SK_U16 Ctrl; pPrt = &pAC->GIni.GP[Port]; Ctrl = 0; /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyXmac: no auto-negotiation Port %d\n", Port)); /* set DuplexMode in Config register */ if (pPrt->PLinkMode == SK_LMODE_FULL) { Ctrl |= PHY_CT_DUP_MD; } /* * Do NOT enable Auto-negotiation here. This would hold * the link down because no IDLEs are transmitted */ } else { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyXmac: with auto-negotiation Port %d\n", Port)); /* set Auto-negotiation advertisement */ /* set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: Ctrl |= PHY_X_AN_HD; break; case SK_LMODE_AUTOFULL: Ctrl |= PHY_X_AN_FD; break; case SK_LMODE_AUTOBOTH: Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, SKERR_HWI_E015MSG); } /* set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl |= PHY_X_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: Ctrl |= PHY_X_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: Ctrl |= PHY_X_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: Ctrl |= PHY_X_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } /* Write AutoNeg Advertisement Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl); /* Restart Auto-negotiation */ Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; } if (DoLoop) { /* set the PHY Loopback bit, too */ Ctrl |= PHY_CT_LOOP; } /* Write to the PHY control register */ SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl); } /* SkXmInitPhyXmac */ /****************************************************************************** * * SkXmInitPhyBcom() - Initialize the Broadcom PHY registers * * Description: initializes all the Broadcom PHY registers * * Note: * * Returns: * nothing */ static void SkXmInitPhyBcom( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { SK_GEPORT *pPrt; SK_U16 Ctrl1; SK_U16 Ctrl2; SK_U16 Ctrl3; SK_U16 Ctrl4; SK_U16 Ctrl5; Ctrl1 = PHY_CT_SP1000; Ctrl2 = 0; Ctrl3 = PHY_SEL_TYPE; Ctrl4 = PHY_B_PEC_EN_LTR; Ctrl5 = PHY_B_AC_TX_TST; pPrt = &pAC->GIni.GP[Port]; /* manually Master/Slave ? */ if (pPrt->PMSMode != SK_MS_MODE_AUTO) { Ctrl2 |= PHY_B_1000C_MSE; if (pPrt->PMSMode == SK_MS_MODE_MASTER) { Ctrl2 |= PHY_B_1000C_MSC; } } /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyBcom: no auto-negotiation Port %d\n", Port)); /* set DuplexMode in Config register */ if (pPrt->PLinkMode == SK_LMODE_FULL) { Ctrl1 |= PHY_CT_DUP_MD; } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { Ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */ } /* * Do NOT enable Auto-negotiation here. This would hold * the link down because no IDLES are transmitted */ } else { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyBcom: with auto-negotiation Port %d\n", Port)); /* set Auto-negotiation advertisement */ /* * Workaround BCOM Errata #1 for the C5 type. * 1000Base-T Link Acquisition Failure in Slave Mode * Set Repeater/DTE bit 10 of the 1000Base-T Control Register */ Ctrl2 |= PHY_B_1000C_RD; /* set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: Ctrl2 |= PHY_B_1000C_AHD; break; case SK_LMODE_AUTOFULL: Ctrl2 |= PHY_B_1000C_AFD; break; case SK_LMODE_AUTOBOTH: Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, SKERR_HWI_E015MSG); } /* set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_B_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: Ctrl3 |= PHY_B_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: Ctrl3 |= PHY_B_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: Ctrl3 |= PHY_B_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } /* Restart Auto-negotiation */ Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; } /* Initialize LED register here? */ /* No. Please do it in SkDgXmitLed() (if required) and swap init order of LEDs and XMAC. (MAl) */ /* Write 1000Base-T Control Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set 1000B-T Ctrl Reg = 0x%04X\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set Auto-Neg.Adv.Reg = 0x%04X\n", Ctrl3)); if (DoLoop) { /* set the PHY Loopback bit, too */ Ctrl1 |= PHY_CT_LOOP; } if (pPrt->PPortUsage == SK_JUMBO_LINK) { /* configure FIFO to high latency for transmission of ext. packets */ Ctrl4 |= PHY_B_PEC_HIGH_LA; /* configure reception of extended packets */ Ctrl5 |= PHY_B_AC_LONG_PACK; SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5); } /* Configure LED Traffic Mode and Jumbo Frame usage if specified */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4); /* Write to the PHY control register */ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Control Reg = 0x%04X\n", Ctrl1)); } /* SkXmInitPhyBcom */ #endif /* GENESIS */ #ifdef YUKON #ifdef SK_PHY_LP_MODE /****************************************************************************** * * SkGmEnterLowPowerMode() * * Description: * This function sets the Marvell Alaska PHY to the low power mode * given by parameter mode. * The following low power modes are available: * * - COMA Mode (Deep Sleep): * The PHY cannot wake up on its own. * * - IEEE 22.2.4.1.5 compatible power down mode * The PHY cannot wake up on its own. * * - energy detect mode * The PHY can wake up on its own by detecting activity * on the CAT 5 cable. * * - energy detect plus mode * The PHY can wake up on its own by detecting activity * on the CAT 5 cable. * Connected devices can be woken up by sending normal link * pulses every second. * * Note: * * Returns: * 0: ok * 1: error */ int SkGmEnterLowPowerMode( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (e.g. MAC_1) */ SK_U8 Mode) /* low power mode */ { SK_U8 LastMode; SK_U8 Byte; SK_U16 Word; SK_U16 ClkDiv; SK_U32 DWord; SK_U32 PowerDownBit; int ChipId; int Ret = 0; if (!(CHIP_ID_YUKON_2(pAC) || (pAC->GIni.GIYukonLite && pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3))) { return(1); } /* save current power mode */ LastMode = pAC->GIni.GP[Port].PPhyPowerState; pAC->GIni.GP[Port].PPhyPowerState = Mode; ChipId = pAC->GIni.GIChipId; SK_DBG_MSG(pAC, SK_DBGMOD_POWM, SK_DBGCAT_CTRL, ("SkGmEnterLowPowerMode: %u\n", Mode)); /* release GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_CLR); /* release GMAC reset */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_RST_CLR); if (ChipId == CHIP_ID_YUKON_EC_U) { /* select page 2 to access MAC control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 2); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); /* allow GMII Power Down */ Word &= ~PHY_M_MAC_GMIF_PUP; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0); } switch (Mode) { /* COMA mode (deep sleep) */ case PHY_PM_DEEP_SLEEP: /* setup General Purpose Control Register */ GM_OUT16(IoC, Port, GM_GP_CTRL, GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); if (CHIP_ID_YUKON_2(pAC)) { /* set power down bit */ PowerDownBit = (Port == MAC_1) ? PCI_Y2_PHY1_POWD : PCI_Y2_PHY2_POWD; if (ChipId != CHIP_ID_YUKON_EC) { if (ChipId == CHIP_ID_YUKON_EC_U) { SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); /* enable Power Down */ Word |= PHY_M_PC_POW_D_ENA; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); } /* set IEEE compatible Power Down Mode (dev. #4.99) */ Ret = SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PHY_CT_PDOWN); } } else { /* apply COMA mode workaround */ (void)SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_ADDR, 0x001f); Ret = SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xfff3); PowerDownBit = PCI_PHY_COMA; } SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_1), &DWord); /* set PHY to PowerDown/COMA Mode */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_1), DWord | PowerDownBit); /* check if this routine was called from a for() loop */ if (pAC->GIni.GIMacsFound == 1 || Port == MAC_2) { /* ASF system clock stopped */ SK_OUT8(IoC, B28_Y2_ASF_STAT_CMD, (SK_U8)Y2_ASF_CLK_HALT); if (ChipId == CHIP_ID_YUKON_EC_U) { /* set GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_SET); /* additional power saving measurements */ SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_4), &DWord); /* set gating core clock for LTSSM in L1 state */ DWord |= (P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) | /* auto clock gated scheme controlled by CLKREQ */ P_ASPM_A1_MODE_SELECT | /* enable Gate Root Core Clock */ P_CLK_GATE_ROOT_COR_ENA); if (HW_FEATURE(pAC, HWF_WA_DEV_4200)) { /* enable Clock Power Management (CLKREQ) */ SK_IN16(IoC, PCI_C(pAC, PEX_LNK_CTRL), &Word); Word |= PEX_LC_CLK_PM_ENA; SK_OUT16(IoC, PCI_C(pAC, PEX_LNK_CTRL), Word); } else { /* force CLKREQ Enable in Our4 (A1b only) */ DWord |= P_ASPM_FORCE_CLKREQ_ENA; } SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_4), DWord); /* set Mask Register for Release/Gate Clock */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_5), P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST | P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE | P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN); } if (HW_FEATURE(pAC, HWF_RED_CORE_CLK_SUP)) { /* divide clock by 4 only for Yukon-EC */ ClkDiv = (ChipId == CHIP_ID_YUKON_EC) ? 1 : 0; /* on Yukon-2 clock select value is 31 */ DWord = (ChipId == CHIP_ID_YUKON_XL) ? (Y2_CLK_DIV_VAL_2(0) | Y2_CLK_SEL_VAL_2(31)) : Y2_CLK_DIV_VAL(ClkDiv); /* check for Yukon-2 dual port PCI-Express adapter */ if (!(pAC->GIni.GIMacsFound == 2 && pAC->GIni.GIPciBus == SK_PEX_BUS)) { /* enable Core Clock Division */ DWord |= Y2_CLK_DIV_ENA; } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set Core Clock: 0x%08X\n", DWord)); /* reduce Core Clock Frequency */ SK_OUT32(IoC, B2_Y2_CLK_CTRL, DWord); } if (HW_FEATURE(pAC, HWF_CLK_GATING_ENABLE)) { /* check for Yukon-2 Rev. A2 */ if (ChipId == CHIP_ID_YUKON_XL && pAC->GIni.GIChipRev > CHIP_REV_YU_XL_A1) { /* enable bits are inverted */ Byte = 0; } else { Byte = (SK_U8)(Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set Clock Gating: 0x%02X\n", Byte)); /* disable MAC/PHY, PCI and Core Clock for both Links */ SK_OUT8(IoC, B2_Y2_CLK_GATE, Byte); } if (pAC->GIni.GIVauxAvail) { /* switch power to VAUX */ SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); } #ifdef DEBUG SK_IN32(IoC, B0_CTST, &DWord); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Ctrl/Stat & Switch: 0x%08x\n", DWord)); #endif /* DEBUG */ if (pAC->GIni.GILevel != SK_INIT_IO && pAC->GIni.GIMacsFound == 1 && pAC->GIni.GIPciBus == SK_PEX_BUS) { if (ChipId == CHIP_ID_YUKON_EC_U) { #ifdef PCI_E_L1_STATE SK_IN16(IoC, PCI_C(pAC, PCI_OUR_REG_1), &Word); /* force to PCIe L1 */ Word |= (SK_U16)PCI_FORCE_PEX_L1; SK_OUT16(IoC, PCI_C(pAC, PCI_OUR_REG_1), Word); #endif /* PCI_E_L1_STATE */ } else { /* switch to D1 state */ SK_OUT8(IoC, PCI_C(pAC, PCI_PM_CTL_STS), PCI_PM_STATE_D1); } } } break; /* IEEE 22.2.4.1.5 compatible power down mode */ case PHY_PM_IEEE_POWER_DOWN: Ret = SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); if (!CHIP_ID_YUKON_2(pAC)) { /* disable MAC 125 MHz clock */ Word |= PHY_M_PC_DIS_125CLK; Word &= ~PHY_M_PC_MAC_POW_UP; } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); /* these register changes must be followed by a software reset */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word | PHY_CT_RESET); /* switch IEEE compatible power down mode on */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word | PHY_CT_PDOWN); break; /* energy detect and energy detect plus mode */ case PHY_PM_ENERGY_DETECT: case PHY_PM_ENERGY_DETECT_PLUS: Ret = SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); /* disable Polarity Reversal */ Word |= PHY_M_PC_POL_R_DIS; if (!CHIP_ID_YUKON_2(pAC)) { /* disable MAC 125 MHz clock */ Word |= PHY_M_PC_DIS_125CLK; } if (ChipId == CHIP_ID_YUKON_FE) { /* enable Energy Detect (sense & pulse) */ Word |= PHY_M_PC_ENA_ENE_DT; } else { /* clear energy detect mode bits */ Word &= ~PHY_M_PC_EN_DET_MSK; Word |= (Mode == PHY_PM_ENERGY_DETECT) ? PHY_M_PC_EN_DET : PHY_M_PC_EN_DET_PLUS; } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); /* these register changes must be followed by a software reset */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); Word |= PHY_CT_RESET; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); if (ChipId == CHIP_ID_YUKON_EC_U) { /* additional power saving measurements */ SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_4), &DWord); /* set gating core clock for LTSSM in L1 state */ DWord |= (P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) | /* Enable Gate Root Core Clock */ P_CLK_GATE_ROOT_COR_ENA); SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_4), DWord); /* set Mask Register for Release/Gate Clock */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_5), P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST | P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE | P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN); #ifdef PCI_E_L1_STATE SK_IN16(IoC, PCI_C(pAC, PCI_OUR_REG_1), &Word); /* enable PCIe L1 on GPHY link down */ Word |= (SK_U16)PCI_ENA_GPHY_LNK; SK_OUT16(IoC, PCI_C(pAC, PCI_OUR_REG_1), Word); #endif /* PCI_E_L1_STATE */ } break; /* don't change current power mode */ default: pAC->GIni.GP[Port].PPhyPowerState = LastMode; Ret = 1; } return(Ret); } /* SkGmEnterLowPowerMode */ /****************************************************************************** * * SkGmLeaveLowPowerMode() * * Description: * Leave the current low power mode and switch to normal mode * * Note: * * Returns: * 0: ok * 1: error */ int SkGmLeaveLowPowerMode( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (e.g. MAC_1) */ { SK_U32 DWord; SK_U32 PowerDownBit; SK_U16 Word; SK_U8 LastMode; int ChipId; int Ret = 0; if (!(CHIP_ID_YUKON_2(pAC) || (pAC->GIni.GIYukonLite && pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3))) { return(1); } /* save current power mode */ LastMode = pAC->GIni.GP[Port].PPhyPowerState; pAC->GIni.GP[Port].PPhyPowerState = PHY_PM_OPERATIONAL_MODE; ChipId = pAC->GIni.GIChipId; SK_DBG_MSG(pAC, SK_DBGMOD_POWM, SK_DBGCAT_CTRL, ("SkGmLeaveLowPowerMode: %u\n", LastMode)); switch (LastMode) { /* COMA mode (deep sleep) */ case PHY_PM_DEEP_SLEEP: if (ChipId == CHIP_ID_YUKON_EC_U) { #ifdef PCI_E_L1_STATE /* set to default value (leave PCIe L1) */ SkPciWriteCfgWord(pAC, PCI_OUR_REG_1, 0); #endif /* PCI_E_L1_STATE */ SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_4), &DWord); DWord &= P_ASPM_CONTROL_MSK; /* set all bits to 0 except bits 15..12 */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_4), DWord); /* set to default value */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_5), 0); } else { SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &Word); /* reset all DState bits */ Word &= ~PCI_PM_STATE_MSK; /* switch to D0 state */ SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, Word); } SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); if (CHIP_ID_YUKON_2(pAC)) { /* disable Core Clock Division */ SK_OUT32(IoC, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); /* set power down bit */ PowerDownBit = (Port == MAC_1) ? PCI_Y2_PHY1_POWD : PCI_Y2_PHY2_POWD; } else { PowerDownBit = PCI_PHY_COMA; } SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_1), &DWord); /* Release PHY from PowerDown/COMA Mode */ SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_1), DWord & ~PowerDownBit); SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); if (CHIP_ID_YUKON_2(pAC)) { if (ChipId == CHIP_ID_YUKON_FE) { /* release IEEE compatible Power Down Mode */ Ret = SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PHY_CT_ANE); } else if (ChipId == CHIP_ID_YUKON_EC_U) { /* release GPHY Control reset */ SK_OUT8(IoC, MR_ADDR(Port, GPHY_CTRL), (SK_U8)GPC_RST_CLR); } } else { SK_IN32(IoC, B2_GP_IO, &DWord); /* set to output */ DWord |= (GP_DIR_9 | GP_IO_9); /* set PHY reset */ SK_OUT32(IoC, B2_GP_IO, DWord); DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ /* clear PHY reset */ SK_OUT32(IoC, B2_GP_IO, DWord); } break; /* IEEE 22.2.4.1.5 compatible power down mode */ case PHY_PM_IEEE_POWER_DOWN: if (ChipId != CHIP_ID_YUKON_XL) { Ret = SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); Word &= ~PHY_M_PC_DIS_125CLK; /* enable MAC 125 MHz clock */ Word |= PHY_M_PC_MAC_POW_UP; /* set MAC power up */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); /* these register changes must be followed by a software reset */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); Word |= PHY_CT_RESET; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); } /* switch IEEE compatible power down mode off */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); Word &= ~PHY_CT_PDOWN; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); break; /* energy detect and energy detect plus mode */ case PHY_PM_ENERGY_DETECT: case PHY_PM_ENERGY_DETECT_PLUS: if (ChipId != CHIP_ID_YUKON_XL) { Ret = SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); if (ChipId == CHIP_ID_YUKON_FE) { /* disable Energy Detect */ Word &= ~PHY_M_PC_ENA_ENE_DT; } else { /* disable energy detect mode & enable MAC 125 MHz clock */ Word &= ~(PHY_M_PC_EN_DET_MSK | PHY_M_PC_DIS_125CLK); } /* enable Polarity Reversal */ Word &= ~PHY_M_PC_POL_R_DIS; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); /* these register changes must be followed by a software reset */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); Word |= PHY_CT_RESET; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); } break; /* don't change current power mode */ default: pAC->GIni.GP[Port].PPhyPowerState = LastMode; Ret = 1; } return(Ret); } /* SkGmLeaveLowPowerMode */ #endif /* SK_PHY_LP_MODE */ /****************************************************************************** * * SkGmInitPhyMarv() - Initialize the Marvell PHY registers * * Description: initializes all the Marvell PHY registers * * Note: * * Returns: * nothing */ static void SkGmInitPhyMarv( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { SK_GEPORT *pPrt; SK_BOOL AutoNeg; SK_U16 PhyCtrl; SK_U16 C1000BaseT; SK_U16 AutoNegAdv; SK_U8 PauseMode; int ChipId; int Mode; #ifndef VCPU SK_U16 Word; SK_U16 PageReg; #ifndef SK_SLIM SK_U16 LoopSpeed; #endif /* !SK_SLIM */ SK_U16 ExtPhyCtrl; SK_U16 BlinkCtrl; SK_U16 LedCtrl; SK_U16 LedConf; SK_U16 LedOver; #ifndef SK_DIAG SK_EVPARA Para; #endif /* !SK_DIAG */ #if defined(SK_DIAG) || defined(DEBUG) SK_U16 PhyStat; SK_U16 PhyStat1; SK_U16 PhySpecStat; #endif /* SK_DIAG || DEBUG */ #endif /* !VCPU */ /* set Pause On */ PauseMode = (SK_U8)GMC_PAUSE_ON; pPrt = &pAC->GIni.GP[Port]; ChipId = pAC->GIni.GIChipId; /* Auto-negotiation ? */ AutoNeg = pPrt->PLinkMode != SK_LMODE_HALF && pPrt->PLinkMode != SK_LMODE_FULL; SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyMarv: Port %d, Auto-neg. %s, LMode %d, LSpeed %d, FlowC %d\n", Port, AutoNeg ? "ON" : "OFF", pPrt->PLinkMode, pPrt->PLinkSpeed, pPrt->PFlowCtrlMode)); #ifndef VCPU /* read Id from PHY */ if (SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1) != 0) { #ifndef SK_DIAG Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); #endif /* !SK_DIAG */ return; } if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) { #ifndef SK_SLIM if (DoLoop) { /* special setup for PHY 88E1112 */ if (ChipId == CHIP_ID_YUKON_XL) { LoopSpeed = pPrt->PLinkSpeed; if (LoopSpeed == SK_LSPEED_AUTO) { /* force 1000 Mbps */ LoopSpeed = SK_LSPEED_1000MBPS; } LoopSpeed += 2; /* save page register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_ADR, &PageReg); /* select page 2 to access MAC control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 2); /* set MAC interface speed */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, LoopSpeed << 4); /* restore page register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, PageReg); /* disable link pulses */ Word = PHY_M_PC_DIS_LINK_P; } else { /* set 'MAC Power up'-bit, set Manual MDI configuration */ Word = PHY_M_PC_MAC_POW_UP; } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); } else #endif /* !SK_SLIM */ if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO && !(ChipId == CHIP_ID_YUKON_XL || ChipId == CHIP_ID_YUKON_EC_U)) { /* Read Ext. PHY Specific Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | PHY_M_EC_MAC_S_MSK); ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ); /* on PHY 88E1040 Rev.D0 (and newer) downshift control changed */ if (pAC->GIni.GIYukonLite || ChipId == CHIP_ID_YUKON_EC) { /* set downshift counter to 3x and enable downshift */ ExtPhyCtrl |= PHY_M_EC_DSC_2(2) | PHY_M_EC_DOWN_S_ENA; } else { /* set master & slave downshift counter to 1x */ ExtPhyCtrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set Ext. PHY Ctrl = 0x%04X\n", ExtPhyCtrl)); } } if (CHIP_ID_YUKON_2(pAC)) { /* Read PHY Specific Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &PhyCtrl); if (!DoLoop && pAC->GIni.GICopperType) { if (ChipId == CHIP_ID_YUKON_FE) { /* enable Automatic Crossover (!!! Bits 5..4) */ PhyCtrl |= (SK_U16)(PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1); } else { #ifndef SK_DIAG /* disable Energy Detect Mode */ PhyCtrl &= ~PHY_M_PC_EN_DET_MSK; #endif /* !SK_DIAG */ /* enable Automatic Crossover */ PhyCtrl |= (SK_U16)PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); /* downshift on PHY 88E1112 and 88E1149 is changed */ if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO && (ChipId == CHIP_ID_YUKON_XL || ChipId == CHIP_ID_YUKON_EC_U)) { /* set downshift counter to 3x and enable downshift */ PhyCtrl &= ~PHY_M_PC_DSC_MSK; PhyCtrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } } } /* workaround for deviation #4.88 (CRC errors) */ else { /* disable Automatic Crossover */ PhyCtrl &= ~PHY_M_PC_MDIX_MSK; } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PhyCtrl); } /* special setup for PHY 88E1112 Fiber */ if (ChipId == CHIP_ID_YUKON_XL && !pAC->GIni.GICopperType) { /* select 1000BASE-X only mode in MAC Specific Ctrl Reg. */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 2); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); Word &= ~PHY_M_MAC_MD_MSK; Word |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); /* select page 1 to access Fiber registers */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 1); if (pAC->GIni.GIPmdTyp == 'P') { /* for SFP-module set SIGDET polarity to low */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); Word |= PHY_M_FIB_SIGD_POL; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); } } /* Read PHY Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); #ifndef SK_SLIM if (!AutoNeg) { /* disable Auto-negotiation */ PhyCtrl &= ~PHY_CT_ANE; } #endif /* !SK_SLIM */ PhyCtrl |= PHY_CT_RESET; /* assert software reset */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); #endif /* !VCPU */ PhyCtrl = 0 /* PHY_CT_COL_TST */; C1000BaseT = 0; AutoNegAdv = PHY_SEL_TYPE; #ifndef SK_SLIM /* manually Master/Slave ? */ if (pPrt->PMSMode != SK_MS_MODE_AUTO) { /* enable Manual Master/Slave */ C1000BaseT |= PHY_M_1000C_MSE; if (pPrt->PMSMode == SK_MS_MODE_MASTER) { C1000BaseT |= PHY_M_1000C_MSC; /* set it to Master */ } } #endif /* !SK_SLIM */ /* Auto-negotiation ? */ if (!AutoNeg) { #ifndef SK_SLIM if (pPrt->PLinkMode == SK_LMODE_FULL) { /* set Full Duplex Mode */ PhyCtrl |= PHY_CT_DUP_MD; } /* set Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { C1000BaseT |= PHY_M_1000C_MSE; /* set it to Slave */ } /* set Speed */ switch (pPrt->PLinkSpeed) { case SK_LSPEED_AUTO: case SK_LSPEED_1000MBPS: PhyCtrl |= (((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) ? PHY_CT_SP1000 : PHY_CT_SP100); break; case SK_LSPEED_100MBPS: PhyCtrl |= PHY_CT_SP100; break; case SK_LSPEED_10MBPS: break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019, SKERR_HWI_E019MSG); } if ((pPrt->PFlowCtrlMode == SK_FLOW_STAT_NONE) || /* disable Pause also for 10/100 Mbps in half duplex mode */ ((ChipId != CHIP_ID_YUKON_EC_U) && (pPrt->PLinkMode == SK_LMODE_HALF) && ((pPrt->PLinkSpeed == SK_LSPEED_STAT_100MBPS) || (pPrt->PLinkSpeed == SK_LSPEED_STAT_10MBPS)))) { /* set Pause Off */ PauseMode = (SK_U8)GMC_PAUSE_OFF; } SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), PauseMode); if (!DoLoop) { /* assert software reset */ PhyCtrl |= PHY_CT_RESET; } #endif /* !SK_SLIM */ } else { /* set Auto-negotiation advertisement */ if (pAC->GIni.GICopperType) { /* set Speed capabilities */ switch (pPrt->PLinkSpeed) { case SK_LSPEED_AUTO: if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) { C1000BaseT |= PHY_M_1000C_AFD; #ifdef xSK_DIAG C1000BaseT |= PHY_M_1000C_AHD; #endif /* SK_DIAG */ } AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | PHY_M_AN_10_FD | PHY_M_AN_10_HD; break; case SK_LSPEED_1000MBPS: if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) { C1000BaseT |= PHY_M_1000C_AFD; #ifdef xSK_DIAG C1000BaseT |= PHY_M_1000C_AHD; #endif /* SK_DIAG */ } break; case SK_LSPEED_100MBPS: if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_100MBPS) != 0) { AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | /* advertise 10Base-T also */ PHY_M_AN_10_FD | PHY_M_AN_10_HD; } break; case SK_LSPEED_10MBPS: if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_10MBPS) != 0) { AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD; } break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019, SKERR_HWI_E019MSG); } /* set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: C1000BaseT &= ~PHY_M_1000C_AFD; AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD); break; case SK_LMODE_AUTOFULL: C1000BaseT &= ~PHY_M_1000C_AHD; AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD); break; case SK_LMODE_AUTOBOTH: break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, SKERR_HWI_E015MSG); } /* set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_B_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: AutoNegAdv |= PHY_B_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: AutoNegAdv |= PHY_B_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: AutoNegAdv |= PHY_B_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } } else { /* special defines for FIBER (88E1040S only) */ /* set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: AutoNegAdv |= PHY_M_AN_1000X_AHD; break; case SK_LMODE_AUTOFULL: AutoNegAdv |= PHY_M_AN_1000X_AFD; break; case SK_LMODE_AUTOBOTH: AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, SKERR_HWI_E015MSG); } /* set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: AutoNegAdv |= PHY_M_P_NO_PAUSE_X; break; case SK_FLOW_MODE_LOC_SEND: AutoNegAdv |= PHY_M_P_ASYM_MD_X; break; case SK_FLOW_MODE_SYMMETRIC: AutoNegAdv |= PHY_M_P_SYM_MD_X; break; case SK_FLOW_MODE_SYM_OR_REM: AutoNegAdv |= PHY_M_P_BOTH_MD_X; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } } if (!DoLoop) { /* Restart Auto-negotiation */ PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG; } } #ifdef VCPU /* * E-mail from Gu Lin (08-03-2002): */ /* Program PHY register 30 as 16'h0708 for simulation speed up */ SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */); VCpuWait(2000); #else /* !VCPU */ if (ChipId != CHIP_ID_YUKON_FE) { /* Write 1000Base-T Control Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set 1000B-T Ctrl = 0x%04X\n", C1000BaseT)); } /* Write AutoNeg Advertisement Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set Auto-Neg.Adv. = 0x%04X\n", AutoNegAdv)); #endif /* !VCPU */ #ifndef SK_SLIM if (DoLoop) { /* set the PHY Loopback bit */ PhyCtrl |= PHY_CT_LOOP; } #endif /* !SK_SLIM */ /* Write to the PHY Control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Set PHY Ctrl Reg. = 0x%04X\n", PhyCtrl)); #ifdef VCPU VCpuWait(2000); #else /* !VCPU */ LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS); LedOver = 0; BlinkCtrl = pAC->GIni.GILedBlinkCtrl; if ((BlinkCtrl & SK_ACT_LED_BLINK) != 0) { if (ChipId == CHIP_ID_YUKON_FE) { /* on 88E3082 these bits are at 11..9 (shifted left) */ LedCtrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1; SkGmPhyRead(pAC, IoC, Port, PHY_MARV_FE_LED_PAR, &Word); /* delete ACT LED control bits */ Word &= ~PHY_M_FELP_LED1_MSK; /* change ACT LED control to blink mode */ Word |= PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_FE_LED_PAR, Word); } else if (ChipId == CHIP_ID_YUKON_XL || ChipId == CHIP_ID_YUKON_EC_U) { /* save page register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_ADR, &PageReg); /* select page 3 to access LED control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 3); LedConf = PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ PHY_M_LEDC_STA0_CTRL(7); /* 1000 Mbps */ Mode = 7; /* 10 Mbps: On */ if (ChipId == CHIP_ID_YUKON_XL) { /* set Polarity Control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_STAT, (SK_U16) (PHY_M_POLC_LS1_P_MIX(4) | PHY_M_POLC_IS0_P_MIX(4) | PHY_M_POLC_LOS_CTRL(2) | PHY_M_POLC_INIT_CTRL(2) | PHY_M_POLC_STA1_CTRL(2) | PHY_M_POLC_STA0_CTRL(2))); } else if (ChipId == CHIP_ID_YUKON_EC_U) { /* check for LINK_LED mux */ if ((BlinkCtrl & SK_LED_LINK_MUX_P60) != 0) { SK_IN16(pAC, GPHY_CTRL, &Word); Word |= GPC_LED_CONF_VAL(4); /* set GPHY LED Config */ SK_OUT16(pAC, GPHY_CTRL, Word); } else { Mode = 8; /* Forced Off */ } /* set Blink Rate in LED Timer Control Register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, LedCtrl | (SK_U16)PHY_M_LED_BLINK_RT(BLINK_84MS)); } LedConf |= PHY_M_LEDC_INIT_CTRL(Mode); /* set LED Function Control register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, LedConf); #if (defined(SK_DIAG) || (defined(DEBUG) && !defined(SK_SLIM))) /* select page 6 to access Packet Generation register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 6); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &PhyCtrl); PhyCtrl |= BIT_4S; /* enable CRC checker */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PhyCtrl); #endif /* SK_DIAG || (DEBUG && !SK_SLIM) */ /* restore page register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, PageReg); } else { /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ LedCtrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; /* on PHY 88E1111 there is a change for LED control */ if (ChipId == CHIP_ID_YUKON_EC && (BlinkCtrl & SK_DUAL_LED_ACT_LNK) != 0) { /* Yukon-EC needs setting of 2 bits: 0,6=11) */ LedCtrl |= PHY_M_LEDC_TX_C_LSB; } /* turn off the Rx LED (LED_RX) */ LedOver |= PHY_M_LED_MO_RX(MO_LED_OFF); } } if ((BlinkCtrl & SK_DUP_LED_NORMAL) != 0) { /* disable blink mode (LED_DUPLEX) on collisions */ LedCtrl |= PHY_M_LEDC_DP_CTRL; } if (ChipId == CHIP_ID_YUKON_EC_U) { if (pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A1) { /* apply fixes in PHY AFE */ SkGmPhyWrite(pAC, IoC, Port, 22, 255); /* increase differential signal amplitude in 10BASE-T */ SkGmPhyWrite(pAC, IoC, Port, 24, 0xaa99); SkGmPhyWrite(pAC, IoC, Port, 23, 0x2011); /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ SkGmPhyWrite(pAC, IoC, Port, 24, 0xa204); SkGmPhyWrite(pAC, IoC, Port, 23, 0x2002); /* set page register to 0 */ SkGmPhyWrite(pAC, IoC, Port, 22, 0); } } else { /* no effect on Yukon-XL */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl); #ifndef SK_SLIM if ((BlinkCtrl & SK_LED_LINK100_ON) != 0) { /* only in forced 100 Mbps mode */ if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) { /* turn on 100 Mbps LED (LED_LINK100) */ LedOver |= PHY_M_LED_MO_100(MO_LED_ON); } } #endif /* !SK_SLIM */ if (LedOver != 0) { /* set Manual LED Override */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER, LedOver); } } #ifdef SK_DIAG c_print("Set PHY Ctrl = 0x%04X\n", PhyCtrl); c_print("Set 1000 B-T = 0x%04X\n", C1000BaseT); c_print("Set Auto-Neg = 0x%04X\n", AutoNegAdv); c_print("Set Ext Ctrl = 0x%04X\n", ExtPhyCtrl); #endif /* SK_DIAG */ #if (defined(SK_DIAG) || (defined(DEBUG) && !defined(SK_SLIM))) /* Read PHY Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Ctrl Reg. = 0x%04X\n", PhyCtrl)); /* Read AutoNeg Advertisement Register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Auto-Neg.Adv. = 0x%04X\n", AutoNegAdv)); if (ChipId != CHIP_ID_YUKON_FE) { /* Read 1000Base-T Control Register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("1000B-T Ctrl = 0x%04X\n", C1000BaseT)); /* Read Ext. PHY Specific Control */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Ext. PHY Ctrl = 0x%04X\n", ExtPhyCtrl)); } /* Read PHY Status */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Stat Reg. = 0x%04X\n", PhyStat)); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Stat Reg. = 0x%04X\n", PhyStat1)); /* Read PHY Specific Status */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Spec Stat = 0x%04X\n", PhySpecStat)); #endif /* SK_DIAG || (DEBUG && !SK_SLIM) */ #ifdef SK_DIAG c_print("PHY Ctrl Reg = 0x%04X\n", PhyCtrl); c_print("PHY 1000 Reg = 0x%04X\n", C1000BaseT); c_print("PHY AnAd Reg = 0x%04X\n", AutoNegAdv); c_print("Ext Ctrl Reg = 0x%04X\n", ExtPhyCtrl); c_print("PHY Stat Reg = 0x%04X\n", PhyStat); c_print("PHY Stat Reg = 0x%04X\n", PhyStat1); c_print("PHY Spec Reg = 0x%04X\n", PhySpecStat); #endif /* SK_DIAG */ /* enable PHY interrupts */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, (SK_U16)PHY_M_DEF_MSK); #endif /* !VCPU */ } /* SkGmInitPhyMarv */ #endif /* YUKON */ #ifdef OTHER_PHY /****************************************************************************** * * SkXmInitPhyLone() - Initialize the Level One PHY registers * * Description: initializes all the Level One PHY registers * * Note: * * Returns: * nothing */ static void SkXmInitPhyLone( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { SK_GEPORT *pPrt; SK_U16 Ctrl1; SK_U16 Ctrl2; SK_U16 Ctrl3; Ctrl1 = PHY_CT_SP1000; Ctrl2 = 0; Ctrl3 = PHY_SEL_TYPE; pPrt = &pAC->GIni.GP[Port]; /* manually Master/Slave ? */ if (pPrt->PMSMode != SK_MS_MODE_AUTO) { Ctrl2 |= PHY_L_1000C_MSE; if (pPrt->PMSMode == SK_MS_MODE_MASTER) { Ctrl2 |= PHY_L_1000C_MSC; } } /* Auto-negotiation ? */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { /* * level one spec say: "1000 Mbps: manual mode not allowed" * but lets see what happens... */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyLone: no auto-negotiation Port %d\n", Port)); /* set DuplexMode in Config register */ if (pPrt->PLinkMode == SK_LMODE_FULL) { Ctrl1 |= PHY_CT_DUP_MD; } /* Determine Master/Slave manually if not already done */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { Ctrl2 |= PHY_L_1000C_MSE; /* set it to Slave */ } /* * Do NOT enable Auto-negotiation here. This would hold * the link down because no IDLES are transmitted */ } else { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("InitPhyLone: with auto-negotiation Port %d\n", Port)); /* set Auto-negotiation advertisement */ /* set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: Ctrl2 |= PHY_L_1000C_AHD; break; case SK_LMODE_AUTOFULL: Ctrl2 |= PHY_L_1000C_AFD; break; case SK_LMODE_AUTOBOTH: Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, SKERR_HWI_E015MSG); } /* set Flow-control capabilities */ switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: Ctrl3 |= PHY_L_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: Ctrl3 |= PHY_L_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: Ctrl3 |= PHY_L_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: Ctrl3 |= PHY_L_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } /* Restart Auto-negotiation */ Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG; } /* Write 1000Base-T Control Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("1000B-T Ctrl Reg = 0x%04X\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Auto-Neg.Adv.Reg = 0x%04X\n", Ctrl3)); if (DoLoop) { /* set the PHY Loopback bit, too */ Ctrl1 |= PHY_CT_LOOP; } /* Write to the PHY control register */ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Control Reg = 0x%04X\n", Ctrl1)); } /* SkXmInitPhyLone */ /****************************************************************************** * * SkXmInitPhyNat() - Initialize the National PHY registers * * Description: initializes all the National PHY registers * * Note: * * Returns: * nothing */ static void SkXmInitPhyNat( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { /* todo: National */ } /* SkXmInitPhyNat */ #endif /* OTHER_PHY */ /****************************************************************************** * * SkMacInitPhy() - Initialize the PHY registers * * Description: calls the Init PHY routines dep. on board type * * Note: * * Returns: * nothing */ void SkMacInitPhy( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a PHY LoopBack be set-up? */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; #ifdef GENESIS if (pAC->GIni.GIGenesis) { switch (pPrt->PhyType) { case SK_PHY_XMAC: SkXmInitPhyXmac(pAC, IoC, Port, DoLoop); break; case SK_PHY_BCOM: SkXmInitPhyBcom(pAC, IoC, Port, DoLoop); break; #ifdef OTHER_PHY case SK_PHY_LONE: SkXmInitPhyLone(pAC, IoC, Port, DoLoop); break; case SK_PHY_NAT: SkXmInitPhyNat(pAC, IoC, Port, DoLoop); break; #endif /* OTHER_PHY */ } } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { SkGmInitPhyMarv(pAC, IoC, Port, DoLoop); } #endif /* YUKON */ } /* SkMacInitPhy */ #ifdef GENESIS /****************************************************************************** * * SkXmAutoNegDoneXmac() - Auto-negotiation handling * * Description: * This function handles the auto-negotiation if the Done bit is set. * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ static int SkXmAutoNegDoneXmac( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 ResAb; /* Resolved Ability */ SK_U16 LinkPartAb; /* Link Partner Ability */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegDoneXmac, Port %d\n", Port)); pPrt = &pAC->GIni.GP[Port]; /* Get PHY parameters */ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LinkPartAb); SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb); if ((LinkPartAb & PHY_X_AN_RFB) != 0) { /* At least one of the remote fault bit is set */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_OTHER); } /* Check Duplex mismatch */ if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Duplex mode mismatch Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_DUP_CAP); } /* Check PAUSE mismatch */ /* We are NOT using chapter 4.23 of the Xaqti manual */ /* We are using IEEE 802.3z/D5.0 Table 37-4 */ if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC || pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) && (LinkPartAb & PHY_X_P_SYM_MD) != 0) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; } else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM && (LinkPartAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) { /* enable PAUSE receive, disable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; } else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND && (LinkPartAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) { /* disable PAUSE receive, enable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; } else { /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneXmac */ /****************************************************************************** * * SkXmAutoNegDoneBcom() - Auto-negotiation handling * * Description: * This function handles the auto-negotiation if the Done bit is set. * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ static int SkXmAutoNegDoneBcom( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; #ifdef TEST_ONLY SK_U16 ResAb; /* Resolved Ability */ #endif SK_U16 LinkPartAb; /* Link Partner Ability */ SK_U16 AuxStat; /* Auxiliary Status */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegDoneBcom, Port %d\n", Port)); pPrt = &pAC->GIni.GP[Port]; /* Get PHY parameters */ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LinkPartAb); #ifdef TEST_ONLY SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); #endif SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat); if ((LinkPartAb & PHY_B_AN_RF) != 0) { /* Remote fault bit is set: Error */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_OTHER); } /* Check Duplex mismatch */ if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } else { /* Error */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Duplex mode mismatch Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_DUP_CAP); } #ifdef TEST_ONLY /* Check Master/Slave resolution */ if ((ResAb & PHY_B_1000S_MSF) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("Master/Slave Fault Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PMSStatus = SK_MS_STAT_FAULT; return(SK_AND_OTHER); } pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE; #endif /* Check PAUSE mismatch ??? */ /* We are using IEEE 802.3z/D5.0 Table 37-4 */ if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; } else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) { /* enable PAUSE receive, disable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; } else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) { /* disable PAUSE receive, enable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; } else { /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; return(SK_AND_OK); } /* SkXmAutoNegDoneBcom */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmAutoNegDoneMarv() - Auto-negotiation handling * * Description: * This function handles the auto-negotiation if the Done bit is set. * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ static int SkGmAutoNegDoneMarv( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 ResAb; /* Resolved Ability */ SK_U16 AuxStat; /* Auxiliary Status */ SK_U8 PauseMode; /* Pause Mode */ #ifndef SK_SLIM SK_U16 LinkPartAb; /* Link Partner Ability */ #ifndef SK_DIAG SK_EVPARA Para; #endif /* !SK_DIAG */ #endif /* !SK_SLIM */ /* set Pause On */ PauseMode = (SK_U8)GMC_PAUSE_ON; SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegDoneMarv, Port %d\n", Port)); pPrt = &pAC->GIni.GP[Port]; /* Get PHY parameters */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LinkPartAb); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Link P.Abil. = 0x%04X\n", LinkPartAb)); if ((LinkPartAb & PHY_M_AN_RF) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_OTHER); } #ifndef SK_SLIM if (pAC->GIni.GICopperType) { /* Read PHY Auto-Negotiation Expansion */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &LinkPartAb); if ((LinkPartAb & PHY_ANE_LP_CAP) == 0) { #ifndef SK_DIAG SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Link Partner not Auto-Neg. able, AN Exp.: 0x%04X\n", LinkPartAb)); #ifndef NDIS_MINIPORT_DRIVER SK_ERR_LOG(pAC, SK_ERRCL_CONFIG, SKERR_HWI_E025, SKERR_HWI_E025MSG); #endif Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_LIPA_NOT_AN_ABLE, Para); #else c_print("Link Partner not Auto-Neg. able, AN Exp.: 0x%04X\n", LinkPartAb); #endif /* !SK_DIAG */ if (HW_FEATURE(pAC, HWF_FORCE_AUTO_NEG) && pPrt->PLinkModeConf < SK_LMODE_AUTOHALF) { /* set used link speed */ pPrt->PLinkSpeedUsed = pPrt->PLinkSpeed; /* Set Link Mode Status */ pPrt->PLinkModeStatus = (pPrt->PLinkModeConf == SK_LMODE_FULL) ? SK_LMODE_STAT_FULL : SK_LMODE_STAT_HALF; return(SK_AND_OK); } } } #endif /* !SK_SLIM */ if ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) { SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb); /* Check Master/Slave resolution */ if ((ResAb & PHY_B_1000S_MSF) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("Master/Slave Fault Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PMSStatus = SK_MS_STAT_FAULT; return(SK_AND_OTHER); } pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE; } /* Read PHY Specific Status */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat); /* Check Speed & Duplex resolved */ if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; return(SK_AND_DUP_CAP); } pPrt->PLinkModeStatus = (SK_U8)(((AuxStat & PHY_M_PS_FULL_DUP) != 0) ? SK_LMODE_STAT_AUTOFULL : SK_LMODE_STAT_AUTOHALF); if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) { /* set used link speed */ pPrt->PLinkSpeedUsed = (SK_U8)(((AuxStat & PHY_M_PS_SPEED_100) != 0) ? SK_LSPEED_STAT_100MBPS : SK_LSPEED_STAT_10MBPS); } else { /* set used link speed */ switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) { case (unsigned)PHY_M_PS_SPEED_1000: pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; break; case PHY_M_PS_SPEED_100: pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; default: pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; } if (pAC->GIni.GIChipId == CHIP_ID_YUKON_XL || pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U) { /* Tx & Rx Pause Enabled bits are at 9..8 */ AuxStat >>= 6; if (!pAC->GIni.GICopperType) { /* always 1000 Mbps on fiber */ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; } } AuxStat &= PHY_M_PS_PAUSE_MSK; /* We are using IEEE 802.3z/D5.0 Table 37-4 */ if (AuxStat == PHY_M_PS_PAUSE_MSK) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; } else if (AuxStat == PHY_M_PS_RX_P_EN) { /* enable PAUSE receive, disable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; } else if (AuxStat == PHY_M_PS_TX_P_EN) { /* disable PAUSE receive, enable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; } else { /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("LinkSpeedUsed = %d\n", pPrt->PLinkSpeedUsed)); if ((pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE) || /* disable Pause also for 10/100 Mbps in half duplex mode */ ((pAC->GIni.GIChipId != CHIP_ID_YUKON_EC_U) && (pPrt->PLinkSpeedUsed < (SK_U8)SK_LSPEED_STAT_1000MBPS) && pPrt->PLinkModeStatus == (SK_U8)SK_LMODE_STAT_AUTOHALF)) { /* set Pause Off */ PauseMode = (SK_U8)GMC_PAUSE_OFF; } SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), PauseMode); return(SK_AND_OK); } /* SkGmAutoNegDoneMarv */ #endif /* YUKON */ #ifdef OTHER_PHY /****************************************************************************** * * SkXmAutoNegDoneLone() - Auto-negotiation handling * * Description: * This function handles the auto-negotiation if the Done bit is set. * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ static int SkXmAutoNegDoneLone( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 ResAb; /* Resolved Ability */ SK_U16 LinkPartAb; /* Link Partner Ability */ SK_U16 QuickStat; /* Auxiliary Status */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegDoneLone, Port %d\n", Port)); pPrt = &pAC->GIni.GP[Port]; /* Get PHY parameters */ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LinkPartAb); SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb); SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat); if ((LinkPartAb & PHY_L_AN_RF) != 0) { /* Remote fault bit is set */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; return(SK_AND_OTHER); } /* Check Duplex mismatch */ if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; } else { pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; } /* Check Master/Slave resolution */ if ((ResAb & PHY_L_1000S_MSF) != 0) { /* Error */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("Master/Slave Fault Port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PMSStatus = SK_MS_STAT_FAULT; return(SK_AND_OTHER); } pPrt->PMSStatus = ((ResAb & PHY_L_1000S_MSR) != 0) ? (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE; /* Check PAUSE mismatch */ /* We are using IEEE 802.3z/D5.0 Table 37-4 */ /* we must manually resolve the abilities here */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: /* default */ break; case SK_FLOW_MODE_LOC_SEND: if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) == (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) { /* disable PAUSE receive, enable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; } break; case SK_FLOW_MODE_SYMMETRIC: if ((QuickStat & PHY_L_QS_PAUSE) != 0) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; } break; case SK_FLOW_MODE_SYM_OR_REM: if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) == PHY_L_QS_AS_PAUSE) { /* enable PAUSE receive, disable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; } else if ((QuickStat & PHY_L_QS_PAUSE) != 0) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; } break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, SKERR_HWI_E016MSG); } return(SK_AND_OK); } /* SkXmAutoNegDoneLone */ /****************************************************************************** * * SkXmAutoNegDoneNat() - Auto-negotiation handling * * Description: * This function handles the auto-negotiation if the Done bit is set. * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ static int SkXmAutoNegDoneNat( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { /* todo: National */ return(SK_AND_OK); } /* SkXmAutoNegDoneNat */ #endif /* OTHER_PHY */ /****************************************************************************** * * SkMacAutoNegDone() - Auto-negotiation handling * * Description: calls the auto-negotiation done routines dep. on board type * * Returns: * SK_AND_OK o.k. * SK_AND_DUP_CAP Duplex capability error happened * SK_AND_OTHER Other error happened */ int SkMacAutoNegDone( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; int Rtv; Rtv = SK_AND_OK; pPrt = &pAC->GIni.GP[Port]; #ifdef GENESIS if (pAC->GIni.GIGenesis) { switch (pPrt->PhyType) { case SK_PHY_XMAC: Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port); break; case SK_PHY_BCOM: Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port); break; #ifdef OTHER_PHY case SK_PHY_LONE: Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port); break; case SK_PHY_NAT: Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port); break; #endif /* OTHER_PHY */ default: return(SK_AND_OTHER); } } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port); } #endif /* YUKON */ if (Rtv != SK_AND_OK) { return(Rtv); } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNeg done Port %d\n", Port)); /* We checked everything and may now enable the link */ pPrt->PAutoNegFail = SK_FALSE; SkMacRxTxEnable(pAC, IoC, Port); return(SK_AND_OK); } /* SkMacAutoNegDone */ #ifndef SK_SLIM #ifdef GENESIS /****************************************************************************** * * SkXmSetRxTxEn() - Special Set Rx/Tx Enable and some features in XMAC * * Description: * sets MAC or PHY LoopBack and Duplex Mode in the MMU Command Reg. * enables Rx/Tx * * Returns: N/A */ static void SkXmSetRxTxEn( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Para) /* Parameter to set: MAC or PHY LoopBack, Duplex Mode */ { SK_U16 Word; XM_IN16(IoC, Port, XM_MMU_CMD, &Word); switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) { case SK_MAC_LOOPB_ON: Word |= XM_MMU_MAC_LB; break; case SK_MAC_LOOPB_OFF: Word &= ~XM_MMU_MAC_LB; break; } switch (Para & (SK_PHY_LOOPB_ON | SK_PHY_LOOPB_OFF)) { case SK_PHY_LOOPB_ON: Word |= XM_MMU_GMII_LOOP; break; case SK_PHY_LOOPB_OFF: Word &= ~XM_MMU_GMII_LOOP; break; } switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) { case SK_PHY_FULLD_ON: Word |= XM_MMU_GMII_FD; break; case SK_PHY_FULLD_OFF: Word &= ~XM_MMU_GMII_FD; break; } XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_ENA_RX | XM_MMU_ENA_TX); /* dummy read to ensure writing */ XM_IN16(IoC, Port, XM_MMU_CMD, &Word); } /* SkXmSetRxTxEn */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmSetRxTxEn() - Special Set Rx/Tx Enable and some features in GMAC * * Description: * sets MAC LoopBack and Duplex Mode in the General Purpose Control Reg. * enables Rx/Tx * * Returns: N/A */ static void SkGmSetRxTxEn( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Para) /* Parameter to set: MAC LoopBack, Duplex Mode */ { SK_U16 Ctrl; GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl); switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) { case SK_MAC_LOOPB_ON: Ctrl |= GM_GPCR_LOOP_ENA; break; case SK_MAC_LOOPB_OFF: Ctrl &= ~GM_GPCR_LOOP_ENA; break; } switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) { case SK_PHY_FULLD_ON: Ctrl |= GM_GPCR_DUP_FULL; break; case SK_PHY_FULLD_OFF: Ctrl &= ~GM_GPCR_DUP_FULL; break; } GM_OUT16(IoC, Port, GM_GP_CTRL, Ctrl | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); } /* SkGmSetRxTxEn */ #endif /* YUKON */ /****************************************************************************** * * SkMacSetRxTxEn() - Special Set Rx/Tx Enable and parameters * * Description: calls the Special Set Rx/Tx Enable routines dep. on board type * * Returns: N/A */ void SkMacSetRxTxEn( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ int Para) { #ifdef GENESIS if (pAC->GIni.GIGenesis) { SkXmSetRxTxEn(pAC, IoC, Port, Para); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { SkGmSetRxTxEn(pAC, IoC, Port, Para); } #endif /* YUKON */ } /* SkMacSetRxTxEn */ #endif /* !SK_SLIM */ /****************************************************************************** * * SkMacRxTxEnable() - Enable Rx/Tx activity if port is up * * Description: enables Rx/Tx dep. on board type * * Returns: * 0 o.k. * != 0 Error happened */ int SkMacRxTxEnable( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 Reg; /* 16-bit register value */ SK_U16 IntMask; /* MAC interrupt mask */ #ifdef GENESIS SK_U16 SWord; #endif pPrt = &pAC->GIni.GP[Port]; if (!pPrt->PHWLinkUp) { /* The Hardware link is NOT up */ return(0); } if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF || pPrt->PLinkMode == SK_LMODE_AUTOFULL || pPrt->PLinkMode == SK_LMODE_AUTOBOTH) && pPrt->PAutoNegFail) { /* Auto-negotiation is not done or failed */ return(0); } #ifdef GENESIS if (pAC->GIni.GIGenesis) { /* set Duplex Mode and Pause Mode */ SkXmInitDupMd(pAC, IoC, Port); SkXmInitPauseMd(pAC, IoC, Port); /* * Initialize the Interrupt Mask Register. Default IRQs are... * - Link Asynchronous Event * - Link Partner requests config * - Auto Negotiation Done * - Rx Counter Event Overflow * - Tx Counter Event Overflow * - Transmit FIFO Underrun */ IntMask = XM_DEF_MSK; #ifdef DEBUG /* add IRQ for Receive FIFO Overflow */ IntMask &= ~XM_IS_RXF_OV; #endif /* DEBUG */ if (pPrt->PhyType != SK_PHY_XMAC) { /* disable GP0 interrupt bit */ IntMask |= XM_IS_INP_ASS; } XM_OUT16(IoC, Port, XM_IMSK, IntMask); /* get MMU Command Reg. */ XM_IN16(IoC, Port, XM_MMU_CMD, &Reg); if (pPrt->PhyType != SK_PHY_XMAC && (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) { /* set to Full Duplex */ Reg |= XM_MMU_GMII_FD; } switch (pPrt->PhyType) { case SK_PHY_BCOM: /* * Workaround BCOM Errata (#10523) for all BCom Phys * Enable Power Management after link up */ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord); SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, (SK_U16)(SWord & ~PHY_B_AC_DIS_PM)); SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, (SK_U16)PHY_B_DEF_MSK); break; #ifdef OTHER_PHY case SK_PHY_LONE: SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK); break; case SK_PHY_NAT: /* todo National: SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */ /* no interrupts possible from National ??? */ break; #endif /* OTHER_PHY */ } /* enable Rx/Tx */ XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { /* * Initialize the Interrupt Mask Register. Default IRQs are... * - Rx Counter Event Overflow * - Tx Counter Event Overflow * - Transmit FIFO Underrun */ IntMask = GMAC_DEF_MSK; #if (defined(DEBUG) || defined(YUK2)) && (!defined(SK_SLIM)) /* add IRQ for Receive FIFO Overrun */ IntMask |= GM_IS_RX_FF_OR; #endif SK_OUT8(IoC, MR_ADDR(Port, GMAC_IRQ_MSK), (SK_U8)IntMask); /* get General Purpose Control */ GM_IN16(IoC, Port, GM_GP_CTRL, &Reg); if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) { /* set to Full Duplex */ Reg |= GM_GPCR_DUP_FULL; #ifndef SK_SLIM if (HW_FEATURE(pAC, HWF_FORCE_AUTO_NEG) && pPrt->PLinkModeConf < SK_LMODE_AUTOHALF) { /* disable auto-update for speed, duplex and flow-control */ Reg |= GM_GPCR_AU_ALL_DIS; } #endif /* !SK_SLIM */ } /* WA for dev. #4.209 */ if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U && pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A1) { /* enable/disable Store & Forward mode for TX */ SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), pPrt->PLinkSpeedUsed != (SK_U8)SK_LSPEED_STAT_1000MBPS ? TX_STFW_ENA : TX_STFW_DIS); } /* enable Rx/Tx */ GM_OUT16(IoC, Port, GM_GP_CTRL, Reg | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); } #endif /* YUKON */ pAC->GIni.GP[Port].PState = SK_PRT_RUN; return(0); } /* SkMacRxTxEnable */ /****************************************************************************** * * SkMacRxTxDisable() - Disable Receiver and Transmitter * * Description: disables Rx/Tx dep. on board type * * Returns: N/A */ void SkMacRxTxDisable( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_U16 Word; #ifdef GENESIS if (pAC->GIni.GIGenesis) { XM_IN16(IoC, Port, XM_MMU_CMD, &Word); Word &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); XM_OUT16(IoC, Port, XM_MMU_CMD, Word); /* dummy read to ensure writing */ XM_IN16(IoC, Port, XM_MMU_CMD, &Word); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { GM_IN16(IoC, Port, GM_GP_CTRL, &Word); Word &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); GM_OUT16(IoC, Port, GM_GP_CTRL, Word); } #endif /* YUKON */ } /* SkMacRxTxDisable */ /****************************************************************************** * * SkMacIrqDisable() - Disable IRQ from MAC * * Description: sets the IRQ-mask to disable IRQ dep. on board type * * Returns: N/A */ void SkMacIrqDisable( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; #ifdef GENESIS SK_U16 Word; #endif pPrt = &pAC->GIni.GP[Port]; #ifdef GENESIS if (pAC->GIni.GIGenesis) { /* disable all XMAC IRQs */ XM_OUT16(IoC, Port, XM_IMSK, 0xffff); /* disable all PHY interrupts */ switch (pPrt->PhyType) { case SK_PHY_BCOM: /* Make sure that PHY is initialized */ if (pPrt->PState != SK_PRT_RESET) { /* NOT allowed if BCOM is in RESET state */ /* Workaround BCOM Errata (#10523) all BCom */ /* disable Power Management if link is down */ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word); SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, (SK_U16)(Word | PHY_B_AC_DIS_PM)); SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff); } break; #ifdef OTHER_PHY case SK_PHY_LONE: SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0); break; case SK_PHY_NAT: /* todo: National SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */ break; #endif /* OTHER_PHY */ } } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { /* disable all GMAC IRQs */ SK_OUT8(IoC, MR_ADDR(Port, GMAC_IRQ_MSK), 0); #ifndef VCPU /* disable all PHY interrupts */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0); #endif /* !VCPU */ } #endif /* YUKON */ } /* SkMacIrqDisable */ #ifdef SK_DIAG /****************************************************************************** * * SkXmSendCont() - Enable / Disable Send Continuous Mode * * Description: enable / disable Send Continuous Mode on XMAC resp. * Packet Generation on GPHY * * Returns: * nothing */ void SkXmSendCont( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL Enable) /* Enable / Disable */ { SK_U16 Reg; SK_U16 Save; SK_U32 MdReg; if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); if (Enable) { MdReg |= XM_MD_TX_CONT; } else { MdReg &= ~XM_MD_TX_CONT; } /* setup Mode Register */ XM_OUT32(IoC, Port, XM_MODE, MdReg); } else { if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC) { /* select page 18 */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_ADDR, 18); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PAGE_DATA, &Reg); Reg &= ~0x003c; /* clear bits 5..2 */ if (Enable) { /* enable packet generation, 1518 byte length */ Reg |= (BIT_5S | BIT_3S); } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, Reg); } else if (pAC->GIni.GIChipId == CHIP_ID_YUKON_XL) { /* save page register */ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_ADR, &Save); /* select page 6 to access Packet Generation register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 6); SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Reg); Reg &= ~0x003f; /* clear bits 5..0 */ if (Enable) { /* enable packet generation, 1518 byte length */ Reg |= (BIT_3S | BIT_1S); } SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Reg); /* restore page register */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, Save); } } } /* SkXmSendCont */ /****************************************************************************** * * SkMacTimeStamp() - Enable / Disable Time Stamp * * Description: enable / disable Time Stamp generation for Rx packets * * Returns: * nothing */ void SkMacTimeStamp( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL Enable) /* Enable / Disable */ { SK_U32 MdReg; SK_U8 TimeCtrl; if (pAC->GIni.GIGenesis) { XM_IN32(IoC, Port, XM_MODE, &MdReg); if (Enable) { MdReg |= XM_MD_ATS; } else { MdReg &= ~XM_MD_ATS; } /* setup Mode Register */ XM_OUT32(IoC, Port, XM_MODE, MdReg); } else { if (Enable) { TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ; } else { TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ; } /* Start/Stop Time Stamp Timer */ SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl); } } /* SkMacTimeStamp*/ #else /* !SK_DIAG */ #ifdef GENESIS /****************************************************************************** * * SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg * * This function analyses the Interrupt status word. If any of the * Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable * is set true. */ void SkXmAutoNegLipaXmac( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_U16 IStatus) /* Interrupt Status word to analyse */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && (IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegLipa: AutoNeg detected on Port %d, IStatus = 0x%04X\n", Port, IStatus)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } } /* SkXmAutoNegLipaXmac */ #endif /* GENESIS */ /****************************************************************************** * * SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg * * This function analyses the PHY status word. * If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable * is set true. */ void SkMacAutoNegLipaPhy( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_U16 PhyStat) /* PHY Status word to analyse */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && (PhyStat & PHY_ST_AN_OVER) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegLipa: AutoNeg detected on Port %d, PhyStat = 0x%04X\n", Port, PhyStat)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } } /* SkMacAutoNegLipaPhy */ #ifdef GENESIS /****************************************************************************** * * SkXmIrq() - Interrupt Service Routine * * Description: services an Interrupt Request of the XMAC * * Note: * With an external PHY, some interrupt bits are not meaningfull any more: * - LinkAsyncEvent (bit #14) XM_IS_LNK_AE * - LinkPartnerReqConfig (bit #10) XM_IS_LIPA_RC * - Page Received (bit #9) XM_IS_RX_PAGE * - NextPageLoadedForXmt (bit #8) XM_IS_TX_PAGE * - AutoNegDone (bit #7) XM_IS_AND * Also probably not valid any more is the GP0 input bit: * - GPRegisterBit0set XM_IS_INP_ASS * * Returns: * nothing */ static void SkXmIrq( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 IStatus; /* Interrupt status read from the XMAC */ SK_U16 IStatus2; #ifdef SK_SLIM SK_U64 OverflowStatus; #else SK_EVPARA Para; #endif /* SK_SLIM */ pPrt = &pAC->GIni.GP[Port]; XM_IN16(IoC, Port, XM_ISRC, &IStatus); /* LinkPartner Auto-negable? */ if (pPrt->PhyType == SK_PHY_XMAC) { SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus); } else { /* mask bits that are not used with ext. PHY */ IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_TX_PAGE | XM_IS_AND | XM_IS_INP_ASS); } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus)); if (!pPrt->PHWLinkUp) { /* Spurious XMAC interrupt */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("SkXmIrq: spurious interrupt on Port %d\n", Port)); return; } if ((IStatus & XM_IS_INP_ASS) != 0) { /* Reread ISR Register if link is not in sync */ XM_IN16(IoC, Port, XM_ISRC, &IStatus2); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n", Port, IStatus, IStatus2)); IStatus &= ~XM_IS_INP_ASS; IStatus |= IStatus2; } if ((IStatus & XM_IS_LNK_AE) != 0) { /* not used, GP0 is used instead */ } if ((IStatus & XM_IS_TX_ABORT) != 0) { /* not used */ } if ((IStatus & XM_IS_FRC_INT) != 0) { /* not used, use ASIC IRQ instead if needed */ } if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) { SkHWLinkDown(pAC, IoC, Port); /* Signal to RLMT */ Para.Para32[0] = (SK_U32)Port; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); /* Start workaround Errata #2 timer */ SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para); } if ((IStatus & XM_IS_RX_PAGE) != 0) { /* not used */ } if ((IStatus & XM_IS_TX_PAGE) != 0) { /* not used */ } if ((IStatus & XM_IS_AND) != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("SkXmIrq: AND on link that is up Port %d\n", Port)); } if ((IStatus & XM_IS_TSC_OV) != 0) { /* not used */ } /* Combined Tx & Rx Counter Overflow SIRQ Event */ if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) { #ifdef SK_SLIM SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus); #else # ifdef SK_PNMI_SUPPORT Para.Para32[0] = (SK_U32)Port; Para.Para32[1] = (SK_U32)IStatus; SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); # endif #endif /* SK_SLIM */ } if ((IStatus & XM_IS_RXF_OV) != 0) { /* normal situation -> no effect */ #ifdef DEBUG pPrt->PRxOverCnt++; #endif /* DEBUG */ } if ((IStatus & XM_IS_TXF_UR) != 0) { /* may NOT happen -> error log */ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG); } if ((IStatus & XM_IS_TX_COMP) != 0) { /* not served here */ } if ((IStatus & XM_IS_RX_COMP) != 0) { /* not served here */ } } /* SkXmIrq */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmIrq() - Interrupt Service Routine * * Description: services an Interrupt Request of the GMAC * * Note: * * Returns: * nothing */ static void SkGmIrq( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U8 IStatus; /* Interrupt status */ #ifdef SK_SLIM SK_U64 OverflowStatus; #else SK_EVPARA Para; #endif /* SK_SLIM */ pPrt = &pAC->GIni.GP[Port]; SK_IN8(IoC, MR_ADDR(Port, GMAC_IRQ_SRC), &IStatus); #ifdef XXX /* LinkPartner Auto-negable? */ SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus); #endif /* XXX */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("GmacIrq Port %d Isr 0x%02X\n", Port, IStatus)); /* Combined Tx & Rx Counter Overflow SIRQ Event */ if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) { /* these IRQs will be cleared by reading GMACs register */ #ifdef SK_SLIM SkGmOverflowStatus(pAC, IoC, Port, (SK_U16)IStatus, &OverflowStatus); #else # ifdef SK_PNMI_SUPPORT Para.Para32[0] = (SK_U32)Port; Para.Para32[1] = (SK_U32)IStatus; SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); # endif #endif /* SK_SLIM */ } #ifndef SK_SLIM if (IStatus & GM_IS_RX_FF_OR) { /* clear GMAC Rx FIFO Overrun IRQ */ SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO); Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_RX_OVERFLOW, Para); #ifdef DEBUG pPrt->PRxOverCnt++; #endif /* DEBUG */ } #endif /* !SK_SLIM */ if (IStatus & GM_IS_TX_FF_UR) { /* clear GMAC Tx FIFO Underrun IRQ */ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU); /* may NOT happen -> error log */ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG); } if (IStatus & GM_IS_TX_COMPL) { /* not served here */ } if (IStatus & GM_IS_RX_COMPL) { /* not served here */ } } /* SkGmIrq */ #endif /* YUKON */ /****************************************************************************** * * SkMacIrq() - Interrupt Service Routine for MAC * * Description: calls the Interrupt Service Routine dep. on board type * * Returns: * nothing */ void SkMacIrq( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port) /* Port Index (MAC_1 + n) */ { #ifdef GENESIS if (pAC->GIni.GIGenesis) { /* IRQ from XMAC */ SkXmIrq(pAC, IoC, Port); } #endif /* GENESIS */ #ifdef YUKON if (pAC->GIni.GIYukon) { /* IRQ from GMAC */ SkGmIrq(pAC, IoC, Port); } #endif /* YUKON */ } /* SkMacIrq */ #endif /* !SK_DIAG */ #ifdef GENESIS /****************************************************************************** * * SkXmUpdateStats() - Force the XMAC to output the current statistic * * Description: * The XMAC holds its statistic internally. To obtain the current * values a command must be sent so that the statistic data will * be written to a predefined memory area on the adapter. * * Returns: * 0: success * 1: something went wrong */ int SkXmUpdateStats( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 StatReg; int WaitIndex; pPrt = &pAC->GIni.GP[Port]; WaitIndex = 0; /* Send an update command to XMAC specified */ XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC); /* * It is an auto-clearing register. If the command bits * went to zero again, the statistics are transferred. * Normally the command should be executed immediately. * But just to be sure we execute a loop. */ do { XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg); if (++WaitIndex > 10) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG); return(1); } } while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0); return(0); } /* SkXmUpdateStats */ /****************************************************************************** * * SkXmMacStatistic() - Get XMAC counter value * * Description: * Gets the 32bit counter value. Except for the octet counters * the lower 32bit are counted in hardware and the upper 32bit * must be counted in software by monitoring counter overflow interrupts. * * Returns: * 0: success * 1: something went wrong */ int SkXmMacStatistic( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port, /* Port Index (MAC_1 + n) */ SK_U16 StatAddr, /* MIB counter base address */ SK_U32 SK_FAR *pVal) /* Pointer to return statistic value */ { if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG); return(1); } XM_IN32(IoC, Port, StatAddr, pVal); return(0); } /* SkXmMacStatistic */ /****************************************************************************** * * SkXmResetCounter() - Clear MAC statistic counter * * Description: * Force the XMAC to clear its statistic counter. * * Returns: * 0: success * 1: something went wrong */ int SkXmResetCounter( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port) /* Port Index (MAC_1 + n) */ { XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC); /* Clear two times according to XMAC Errata #3 */ XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC); return(0); } /* SkXmResetCounter */ /****************************************************************************** * * SkXmOverflowStatus() - Gets the status of counter overflow interrupt * * Description: * Checks the source causing an counter overflow interrupt. On success the * resulting counter overflow status is written to , whereas the * upper dword stores the XMAC ReceiveCounterEvent register and the lower * dword the XMAC TransmitCounterEvent register. * * Note: * For XMAC the interrupt source is a self-clearing register, so the source * must be checked only once. SIRQ module does another check to be sure * that no interrupt get lost during process time. * * Returns: * 0: success * 1: something went wrong */ int SkXmOverflowStatus( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port, /* Port Index (MAC_1 + n) */ SK_U16 IStatus, /* Interrupt Status from MAC */ SK_U64 SK_FAR *pStatus) /* Pointer for return overflow status value */ { SK_U64 Status; /* Overflow status */ SK_U32 RegVal; Status = 0; if ((IStatus & XM_IS_RXC_OV) != 0) { XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal); Status |= (SK_U64)RegVal << 32; } if ((IStatus & XM_IS_TXC_OV) != 0) { XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal); Status |= (SK_U64)RegVal; } *pStatus = Status; return(0); } /* SkXmOverflowStatus */ #endif /* GENESIS */ #ifdef YUKON /****************************************************************************** * * SkGmUpdateStats() - Force the GMAC to output the current statistic * * Description: * Empty function for GMAC. Statistic data is accessible in direct way. * * Returns: * 0: success * 1: something went wrong */ int SkGmUpdateStats( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port) /* Port Index (MAC_1 + n) */ { return(0); } /****************************************************************************** * * SkGmMacStatistic() - Get GMAC counter value * * Description: * Gets the 32bit counter value. Except for the octet counters * the lower 32bit are counted in hardware and the upper 32bit * must be counted in software by monitoring counter overflow interrupts. * * Returns: * 0: success * 1: something went wrong */ int SkGmMacStatistic( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port, /* Port Index (MAC_1 + n) */ SK_U16 StatAddr, /* MIB counter base address */ SK_U32 SK_FAR *pVal) /* Pointer to return statistic value */ { if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_ERR, ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr)); return(1); } GM_IN32(IoC, Port, StatAddr, pVal); /* dummy read after GM_IN32() */ SK_IN16(IoC, B0_RAP, &StatAddr); return(0); } /* SkGmMacStatistic */ /****************************************************************************** * * SkGmResetCounter() - Clear MAC statistic counter * * Description: * Force GMAC to clear its statistic counter. * * Returns: * 0: success * 1: something went wrong */ int SkGmResetCounter( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port) /* Port Index (MAC_1 + n) */ { SK_U16 Reg; /* PHY Address Register */ SK_U16 Word; int i; GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg); /* set MIB Clear Counter Mode */ GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR); /* read all MIB Counters with Clear Mode set */ for (i = 0; i < GM_MIB_CNT_SIZE; i++) { /* the reset is performed only when the lower 16 bits are read */ GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word); } /* clear MIB Clear Counter Mode */ GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg); return(0); } /* SkGmResetCounter */ /****************************************************************************** * * SkGmOverflowStatus() - Gets the status of counter overflow interrupt * * Description: * Checks the source causing an counter overflow interrupt. On success the * resulting counter overflow status is written to , whereas the * the following bit coding is used: * 63:56 - unused * 55:48 - TxRx interrupt register bit 7:0 * 47:32 - Rx interrupt register * 31:24 - unused * 23:16 - TxRx interrupt register bit 15:8 * 15: 0 - Tx interrupt register * * Returns: * 0: success * 1: something went wrong */ int SkGmOverflowStatus( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ unsigned int Port, /* Port Index (MAC_1 + n) */ SK_U16 IStatus, /* Interrupt Status from MAC */ SK_U64 SK_FAR *pStatus) /* Pointer for return overflow status value */ { SK_U16 RegVal; #ifndef SK_SLIM SK_U64 Status; /* Overflow status */ Status = 0; #endif /* !SK_SLIM */ if ((IStatus & GM_IS_RX_CO_OV) != 0) { /* this register is self-clearing after read */ GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal); #ifndef SK_SLIM Status |= (SK_U64)RegVal << 32; #endif /* !SK_SLIM */ } if ((IStatus & GM_IS_TX_CO_OV) != 0) { /* this register is self-clearing after read */ GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal); #ifndef SK_SLIM Status |= (SK_U64)RegVal; #endif /* !SK_SLIM */ } /* this register is self-clearing after read */ GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal); #ifndef SK_SLIM /* Rx overflow interrupt register bits (LoByte)*/ Status |= (SK_U64)((SK_U8)RegVal) << 48; /* Tx overflow interrupt register bits (HiByte)*/ Status |= (SK_U64)(RegVal >> 8) << 16; *pStatus = Status; #endif /* !SK_SLIM */ /* dummy read after GM_IN16() */ SK_IN16(IoC, B0_RAP, &RegVal); return(0); } /* SkGmOverflowStatus */ #ifndef SK_SLIM /****************************************************************************** * * SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test * * Description: * starts the cable diagnostic test if 'StartTest' is true * gets the results if 'StartTest' is true * * NOTE: this test is meaningful only when link is down * * Returns: * 0: success * 1: no YUKON copper * 2: test in progress */ int SkGmCableDiagStatus( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Port, /* Port Index (MAC_1 + n) */ SK_BOOL StartTest) /* flag for start / get result */ { int i; int CableDiagOffs; int MdiPairs; int Rtv; SK_BOOL FastEthernet; SK_BOOL Yukon2; SK_U16 RegVal; SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; if (pPrt->PhyType != SK_PHY_MARV_COPPER) { return(1); } Yukon2 = pAC->GIni.GIChipId == CHIP_ID_YUKON_XL || pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U; if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) { CableDiagOffs = PHY_MARV_FE_VCT_TX; FastEthernet = SK_TRUE; MdiPairs = 2; } else { CableDiagOffs = Yukon2 ? PHY_MARV_PHY_CTRL : PHY_MARV_CABLE_DIAG; FastEthernet = SK_FALSE; MdiPairs = 4; } if (StartTest) { /* set to RESET to avoid PortCheckUp */ pPrt->PState = SK_PRT_RESET; /* only start the cable test */ if (!FastEthernet) { if ((((pPrt->PhyId1 & PHY_I1_MOD_NUM) >> 4) == 2) && ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4)) { /* apply TDR workaround for model 2, rev. < 4 */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_ADDR, 0x001e); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xcc00); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xc800); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xc400); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xc000); SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PAGE_DATA, 0xc100); } #ifdef YUKON_DBG if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC) { /* set address to 1 for page 1 */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 1); /* disable waiting period */ SkGmPhyWrite(pAC, IoC, Port, CableDiagOffs, PHY_M_CABD_DIS_WAIT); } #endif if (Yukon2) { /* set address to 5 for page 5 */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 5); #ifdef YUKON_DBG /* disable waiting period */ SkGmPhyWrite(pAC, IoC, Port, CableDiagOffs + 1, PHY_M_CABD_DIS_WAIT); #endif } else { /* set address to 0 for MDI[0] (Page 0) */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0); } } else { RegVal = PHY_CT_RESET | PHY_CT_SP100; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, RegVal); #ifdef xYUKON_DBG SkGmPhyRead(pAC, IoC, Port, PHY_MARV_FE_SPEC_2, &RegVal); /* disable waiting period */ RegVal |= PHY_M_FESC_DIS_WAIT; SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_FE_SPEC_2, RegVal); #endif } /* start Cable Diagnostic Test */ SkGmPhyWrite(pAC, IoC, Port, CableDiagOffs, PHY_M_CABD_ENA_TEST); return(0); } /* Read Cable Diagnostic Reg */ Rtv = SkGmPhyRead(pAC, IoC, Port, CableDiagOffs, &RegVal); if (Rtv == 2) { /* PHY read timeout */ return(3); } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("PHY Cable Diag. = 0x%04X\n", RegVal)); if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) { /* test is running */ return(2); } /* get the test results */ for (i = 0; i < MdiPairs; i++) { if (!FastEthernet && !Yukon2) { /* set address to i for MDI[i] */ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i); } /* get Cable Diagnostic values */ SkGmPhyRead(pAC, IoC, Port, CableDiagOffs, &RegVal); pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK); pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13); if (FastEthernet || Yukon2) { /* get next register */ CableDiagOffs++; } } return(0); } /* SkGmCableDiagStatus */ #endif /* !SK_SLIM */ #endif /* YUKON */ /* End of file */ #endif