diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-09-15 19:35:14 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-09-15 19:35:14 -0400 |
commit | 5ad887fa8e875231d72a27c474b10241a5818bf1 (patch) | |
tree | 492292dada18b2db42dc99218345885b1ec43978 /drivers/net/sk98lin/skxmac2.c | |
parent | 62270336e8fdfbea36cb455c27744c23780dbf07 (diff) |
sk98lin: resurrect driver
This reverts commit e1abecc48938fbe1966ea6e78267fc673fa59295.
The driver works on some hardware that skge doesn't handle yet.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sk98lin/skxmac2.c')
-rw-r--r-- | drivers/net/sk98lin/skxmac2.c | 4160 |
1 files changed, 4160 insertions, 0 deletions
diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c new file mode 100644 index 00000000000..b4e75022a65 --- /dev/null +++ b/drivers/net/sk98lin/skxmac2.c @@ -0,0 +1,4160 @@ +/****************************************************************************** + * + * Name: skxmac2.c + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.102 $ + * Date: $Date: 2003/10/02 16:53:58 $ + * Purpose: Contains functions to initialize the MACs and PHYs + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 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. + * + ******************************************************************************/ + +#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 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell."; +#endif + +#ifdef GENESIS +static 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 } +}; +static 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 + */ +void 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); + } +} /* SkXmPhyRead */ + + +/****************************************************************************** + * + * SkXmPhyWrite() - Write to XMAC PHY register + * + * Description: writes a 16-bit word to XMAC PHY or ext. PHY + * + * Returns: + * nothing + */ +void 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); + } +} /* SkXmPhyWrite */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmPhyRead() - Read from GPHY register + * + * Description: reads a 16-bit word from GPHY through MDIO + * + * Returns: + * nothing + */ +void 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 Ctrl; + SK_GEPORT *pPrt; +#ifdef VCPU + u_long SimCyle; + u_long SimLowTime; + + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n", + PhyReg, SimCyle, SimLowTime); +#endif /* VCPU */ + + pPrt = &pAC->GIni.GP[Port]; + + /* set PHY-Register offset and 'Read' OpCode (= 1) */ + *pVal = (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, *pVal); + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* additional check for MDC/MDIO activity */ + if ((Ctrl & GM_SMI_CT_BUSY) == 0) { + *pVal = 0; + return; + } + + *pVal |= GM_SMI_CT_BUSY; + + do { +#ifdef VCPU + VCPUwaitTime(1000); +#endif /* VCPU */ + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* wait until 'ReadValid' is set */ + } while (Ctrl == *pVal); + + /* get the PHY register's value */ + GM_IN16(IoC, Port, GM_SMI_DATA, pVal); + +#ifdef VCPU + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n", + SimCyle, SimLowTime); +#endif /* VCPU */ + +} /* SkGmPhyRead */ + + +/****************************************************************************** + * + * SkGmPhyWrite() - Write to GPHY register + * + * Description: writes a 16-bit word to GPHY through MDIO + * + * Returns: + * nothing + */ +void 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; +#ifdef VCPU + SK_U32 DWord; + u_long SimCyle; + u_long SimLowTime; + + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n", + PhyReg, Val, SimCyle, SimLowTime); +#endif /* VCPU */ + + pPrt = &pAC->GIni.GP[Port]; + + /* write the PHY register's value */ + GM_OUT16(IoC, Port, GM_SMI_DATA, Val); + + /* set PHY-Register offset and 'Write' OpCode (= 0) */ + Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg); + + GM_OUT16(IoC, Port, GM_SMI_CTRL, Val); + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* additional check for MDC/MDIO activity */ + if ((Ctrl & GM_SMI_CT_BUSY) == 0) { + return; + } + + Val |= GM_SMI_CT_BUSY; + + do { +#ifdef VCPU + /* read Timer value */ + SK_IN32(IoC, B2_TI_VAL, &DWord); + + VCPUwaitTime(1000); +#endif /* VCPU */ + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* wait until 'Busy' is cleared */ + } while (Ctrl == Val); + +#ifdef VCPU + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n", + SimCyle, SimLowTime); +#endif /* VCPU */ + +} /* 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 */ +{ + void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal); + + if (pAC->GIni.GIGenesis) { + r_func = SkXmPhyRead; + } + else { + r_func = SkGmPhyRead; + } + + r_func(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 */ +{ + void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val); + + if (pAC->GIni.GIGenesis) { + w_func = SkXmPhyWrite; + } + else { + w_func = SkGmPhyWrite; + } + + w_func(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, /* IO 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, /* IO 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, /* IO 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, /* IO 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; + + if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) { + + GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd); + + RxCmd = OldRxCmd; + + 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 if required */ + if (OldRxCmd != RxCmd) { + 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, &OldRxCmd); + + RxCmd = OldRxCmd; + + 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 Rx control register if required */ + if (OldRxCmd != RxCmd) { + 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, /* IO 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, /* IO 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, /* IO 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] = {0x0000, 0x0000, 0x0000}; + + 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[0]); + } +} /* 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, /* IO 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 + */ +static void SkMacFlushRxFifo( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000}; + + /* 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, /* IO 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, /* IO 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, /* IO 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, 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, + (SK_U16)(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, /* IO 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_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); + +} /* SkGmHardRst */ + + +/****************************************************************************** + * + * SkGmClearRst() - Release the GPHY & GMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkGmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + +#ifdef XXX + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); +#endif /* XXX */ + + /* 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); + } + + /* set HWCFG_MODE */ + DWord = GPC_INT_POL_HI | 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 + VCpuWait(9000); +#endif /* VCPU */ + + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + +#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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + /* 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); + + pPrt->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, /* IO 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].PState = SK_PRT_RESET; + +} /* SkMacHardRst */ + + +#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, /* IO 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) { + /* Port State: 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_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG); + /* 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); + +#ifdef TEST_ONLY + /* temp. code: enable signal detect */ + /* WARNING: do not override GMII setting above */ + XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG); +#endif + } + + /* + * 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 (pAC->GIni.GIPortUsage) { + 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 (pAC->GIni.GIPortUsage == 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, /* IO 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) { + /* Port State: 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_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG); + /* Correct it */ + pPrt->PState = SK_PRT_RESET; + } + } + + if (pPrt->PState == SK_PRT_RESET) { + + SkGmHardRst(pAC, IoC, Port); + + SkGmClearRst(pAC, IoC, Port); + + /* 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: + 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: + /* set Pause Off */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF); + /* 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, GMAC_IRQ_SRC, &SWord); + +#ifndef VCPU + /* read Id from PHY */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1); + + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); +#endif /* VCPU */ + } + + (void)SkGmResetCounter(pAC, IoC, Port); + + /* setup Transmit Control Register */ + GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres)); + + /* setup Receive Control Register */ + GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA | + GM_RXCR_CRC_DIS); + + /* 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 = TX_JAM_LEN_VAL(pPrt->PMacJamLen) | + TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) | + TX_IPG_JAM_DATA(pPrt->PMacJamIpgData); + + GM_OUT16(IoC, Port, GM_TX_PARAM, SWord); + + /* configure the Serial Mode Register */ +#ifdef VCPU + GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord); +#endif /* VCPU */ + + SWord = 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 (pAC->GIni.GIPortUsage == 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 + 4*i, 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); + +#if defined(SK_DIAG) || defined(DEBUG) + /* read General Purpose Status */ + GM_IN16(IoC, Port, GM_GP_STAT, &SWord); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("MAC Stat Reg.=0x%04X\n", SWord)); +#endif /* SK_DIAG || DEBUG */ + +#ifdef SK_DIAG + c_print("MAC Stat Reg=0x%04X\n", SWord); +#endif /* SK_DIAG */ + +} /* 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 + */ +static void SkXmInitDupMd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO 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 + */ +static void SkXmInitPauseMd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO 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, /* IO 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, /* IO 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 (pAC->GIni.GIPortUsage == 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 +/****************************************************************************** + * + * 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, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + SK_U16 PhyCtrl; + SK_U16 C1000BaseT; + SK_U16 AutoNegAdv; + SK_U16 ExtPhyCtrl; + SK_U16 LedCtrl; + SK_BOOL AutoNeg; +#if defined(SK_DIAG) || defined(DEBUG) + SK_U16 PhyStat; + SK_U16 PhyStat1; + SK_U16 PhySpecStat; +#endif /* SK_DIAG || DEBUG */ + + pPrt = &pAC->GIni.GP[Port]; + + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + AutoNeg = SK_FALSE; + } + else { + AutoNeg = SK_TRUE; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyMarv: Port %d, auto-negotiation %s\n", + Port, AutoNeg ? "ON" : "OFF")); + +#ifdef VCPU + VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n", + Port, DoLoop); +#else /* VCPU */ + if (DoLoop) { + /* Set 'MAC Power up'-bit, set Manual MDI configuration */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, + PHY_M_PC_MAC_POW_UP); + } + else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) { + /* 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) | + 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)); + } + + /* Read PHY Control */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); + + if (!AutoNeg) { + /* Disable Auto-negotiation */ + PhyCtrl &= ~PHY_CT_ANE; + } + + 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; + + /* 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 */ + } + } + + /* Auto-negotiation ? */ + if (!AutoNeg) { + + 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 |= PHY_CT_SP1000; + 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 (!DoLoop) { + PhyCtrl |= PHY_CT_RESET; + } + } + else { + /* Set Auto-negotiation advertisement */ + + if (pAC->GIni.GICopperType) { + /* Set Speed capabilities */ + switch (pPrt->PLinkSpeed) { + case SK_LSPEED_AUTO: + C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD; + 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: + C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD; + break; + case SK_LSPEED_100MBPS: + 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: + 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 (88E1011S 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 */ + + /* 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 */ + + if (DoLoop) { + /* Set the PHY Loopback bit */ + PhyCtrl |= PHY_CT_LOOP; + +#ifdef XXX + /* Program PHY register 16 as 16'h0400 to force link good */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD); +#endif /* XXX */ + +#ifndef VCPU + if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) { + /* Write Ext. PHY Specific Control */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, + (SK_U16)((pPrt->PLinkSpeed + 2) << 4)); + } +#endif /* VCPU */ + } +#ifdef TEST_ONLY + else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) { + /* Write PHY Specific Control */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, + PHY_M_PC_EN_DET_MSK); + } +#endif + + /* 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 + + LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS); + + if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) { + LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL; + } + + if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) { + LedCtrl |= PHY_M_LEDC_DP_CTRL; + } + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl); + + if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) { + /* only in forced 100 Mbps mode */ + if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) { + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER, + PHY_M_LED_MO_100(MO_LED_ON)); + } + } + +#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) + /* 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 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 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)); + + /* 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 */ + +#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 */ + +#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, /* IO 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, /* IO 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, /* IO 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* 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, &LPAb); + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb); + + if ((LPAb & PHY_X_AN_RFB) != 0) { + /* At least one of the remote fault bit is set */ + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("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_CTRL, + ("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) && + (LPAb & PHY_X_P_SYM_MD) != 0) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM && + (LPAb & 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 && + (LPAb & 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 LPAb; /* Link Partner Ability */ + SK_U16 AuxStat; /* Auxiliary Status */ + +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + SK_U16 ResAb; /* Resolved Ability */ +#endif /* 0 */ + + 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, &LPAb); +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); +#endif /* 0 */ + + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat); + + if ((LPAb & PHY_B_AN_RF) != 0) { + /* Remote fault bit is set: Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("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_CTRL, + ("AutoNegFail: Duplex mode mismatch Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_DUP_CAP); + } + +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + /* Check Master/Slave resolution */ + if ((ResAb & PHY_B_1000S_MSF) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("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 /* 0 */ + + /* 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 LPAb; /* Link Partner Ability */ + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 AuxStat; /* Auxiliary Status */ + + 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, &LPAb); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Link P.Abil.=0x%04X\n", LPAb)); + + if ((LPAb & PHY_M_AN_RF) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Remote fault bit set Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_OTHER); + } + + 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_CTRL, + ("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_CTRL, + ("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); + } + + if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; + } + else { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; + } + + /* Check PAUSE mismatch ??? */ + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == 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_PAUSE_MSK) == 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; + } + + /* 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; + } + + 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* 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, &LPAb); + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb); + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat); + + if ((LPAb & PHY_L_AN_RF) != 0) { + /* Remote fault bit is set */ + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("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_CTRL, + ("Master/Slave Fault Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return(SK_AND_OTHER); + } + else if (ResAb & PHY_L_1000S_MSR) { + pPrt->PMSStatus = SK_MS_STAT_MASTER; + } + else { + pPrt->PMSStatus = 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, /* IO 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, /* IO 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 */ + + +/****************************************************************************** + * + * 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, /* IO 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; + +#ifdef DEBUG + /* add IRQ for Receive FIFO Overrun */ + IntMask |= GM_IS_RX_FF_OR; +#endif /* DEBUG */ + + SK_OUT8(IoC, 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; + } + + /* enable Rx/Tx */ + GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA | + GM_GPCR_TX_ENA)); + +#ifndef VCPU + /* Enable all PHY interrupts */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, + (SK_U16)PHY_M_DEF_MSK); +#endif /* VCPU */ + } +#endif /* YUKON */ + + 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, /* IO 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); + + 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); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + GM_IN16(IoC, Port, GM_GP_CTRL, &Word); + + GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA | + GM_GPCR_TX_ENA))); + + /* dummy read to ensure writing */ + GM_IN16(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, /* IO 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, 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 + * + * Returns: + * nothing + */ +void SkXmSendCont( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ + SK_U32 MdReg; + + 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); + +} /* 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, /* IO 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, /* IO 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, /* IO 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, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_EVPARA Para; + SK_U16 IStatus; /* Interrupt status read from the XMAC */ + SK_U16 IStatus2; +#ifdef SK_SLIM + SK_U64 OverflowStatus; +#endif + + 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 + Para.Para32[0] = (SK_U32)Port; + Para.Para32[1] = (SK_U32)IStatus; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); +#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, /* IO 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 + + pPrt = &pAC->GIni.GP[Port]; + + SK_IN8(IoC, 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%04X\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, IStatus, &OverflowStatus); +#else + Para.Para32[0] = (SK_U32)Port; + Para.Para32[1] = (SK_U32)IStatus; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); +#endif + } + + 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); +#ifdef DEBUG + pPrt->PRxOverCnt++; +#endif /* DEBUG */ + } + + 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, /* IO 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, /* IO 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, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 StatAddr, /* MIB counter base address */ +SK_U32 SK_FAR *pVal) /* ptr 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, /* IO 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 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 <pStatus>, 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, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 IStatus, /* Interupt Status from MAC */ +SK_U64 SK_FAR *pStatus) /* ptr 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, /* IO 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, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 StatAddr, /* MIB counter base address */ +SK_U32 SK_FAR *pVal) /* ptr 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_CTRL, + ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr)); + return(1); + } + + GM_IN32(IoC, Port, StatAddr, pVal); + + 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, /* IO 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 <pStatus>, whereas the + * the following bit coding is used: + * 63:56 - unused + * 55:48 - TxRx interrupt register bit7:0 + * 32:47 - Rx interrupt register + * 31:24 - unused + * 23:16 - TxRx interrupt register bit15:8 + * 15:0 - Tx interrupt register + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkGmOverflowStatus( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 IStatus, /* Interupt Status from MAC */ +SK_U64 SK_FAR *pStatus) /* ptr for return overflow status value */ +{ + SK_U64 Status; /* Overflow status */ + SK_U16 RegVal; + + Status = 0; + + if ((IStatus & GM_IS_RX_CO_OV) != 0) { + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal); + Status |= (SK_U64)RegVal << 32; + } + + if ((IStatus & GM_IS_TX_CO_OV) != 0) { + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal); + Status |= (SK_U64)RegVal; + } + + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal); + /* 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; + + 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, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL StartTest) /* flag for start / get result */ +{ + int i; + SK_U16 RegVal; + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PhyType != SK_PHY_MARV_COPPER) { + + return(1); + } + + if (StartTest) { + /* only start the cable test */ + if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) { + /* apply TDR workaround from Marvell */ + SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e); + + SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100); + } + + /* set address to 0 for MDI[0] */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0); + + /* Read Cable Diagnostic Reg */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal); + + /* start Cable Diagnostic Test */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, + (SK_U16)(RegVal | PHY_M_CABD_ENA_TEST)); + + return(0); + } + + /* Read Cable Diagnostic Reg */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal); + + 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 < 4; i++) { + /* 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, PHY_MARV_CABLE_DIAG, &RegVal); + + pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK); + + pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13); + } + + return(0); +} /* SkGmCableDiagStatus */ +#endif /* !SK_SLIM */ +#endif /* YUKON */ + +/* End of file */ |