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