Logo Search packages:      
Sourcecode: linux version File versions  Download package

skxmac2.c

/******************************************************************************
 *
 * Name:    skxmac2.c
 * Project: Gigabit Ethernet Adapters, Common Modules
 * Version: $Revision: 1.102 $
 * Date:    $Date: 2003/10/02 16:53:58 $
 * Purpose: Contains functions to initialize the MACs and PHYs
 *
 ******************************************************************************/

/******************************************************************************
 *
 *    (C)Copyright 1998-2002 SysKonnect.
 *    (C)Copyright 2002-2003 Marvell.
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    The information in this file is provided "AS IS" without warranty.
 *
 ******************************************************************************/

#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"

/* typedefs *******************************************************************/

/* BCOM PHY magic pattern list */
typedef struct s_PhyHack {
      int         PhyReg;           /* Phy register */
      SK_U16      PhyVal;           /* Value to write */
} BCOM_HACK;

/* local variables ************************************************************/

#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
static const char SysKonnectFileId[] =
      "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell.";
#endif

#ifdef GENESIS
static BCOM_HACK BcomRegA1Hack[] = {
 { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
 { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
 { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
 { 0, 0 }
};
static BCOM_HACK BcomRegC0Hack[] = {
 { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
 { 0x15, 0x0A04 }, { 0x18, 0x0420 },
 { 0, 0 }
};
#endif

/* function prototypes ********************************************************/
#ifdef GENESIS
static void SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
static void SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
static int  SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
static int  SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
#endif /* GENESIS */
#ifdef YUKON
static void SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL);
static int  SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
#endif /* YUKON */
#ifdef OTHER_PHY
static void SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
static void SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
static int  SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
static int  SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
#endif /* OTHER_PHY */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmPhyRead() - Read from XMAC PHY register
 *
 * Description:   reads a 16-bit word from XMAC PHY or ext. PHY
 *
 * Returns:
 *    nothing
 */
void SkXmPhyRead(
SK_AC *pAC,             /* Adapter Context */
SK_IOC      IoC,              /* I/O Context */
int         Port,             /* Port Index (MAC_1 + n) */
int         PhyReg,                 /* Register Address (Offset) */
SK_U16      SK_FAR *pVal)     /* Pointer to Value */
{
      SK_U16            Mmu;
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];
      
      /* write the PHY register's address */
      XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
      
      /* get the PHY register's value */
      XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
      
      if (pPrt->PhyType != SK_PHY_XMAC) {
            do {
                  XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
                  /* wait until 'Ready' is set */
            } while ((Mmu & XM_MMU_PHY_RDY) == 0);

            /* get the PHY register's value */
            XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
      }
}     /* SkXmPhyRead */


/******************************************************************************
 *
 *    SkXmPhyWrite() - Write to XMAC PHY register
 *
 * Description:   writes a 16-bit word to XMAC PHY or ext. PHY
 *
 * Returns:
 *    nothing
 */
void SkXmPhyWrite(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* I/O Context */
int         Port,       /* Port Index (MAC_1 + n) */
int         PhyReg,           /* Register Address (Offset) */
SK_U16      Val)        /* Value */
{
      SK_U16            Mmu;
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];
      
      if (pPrt->PhyType != SK_PHY_XMAC) {
            do {
                  XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
                  /* wait until 'Busy' is cleared */
            } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
      }
      
      /* write the PHY register's address */
      XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
      
      /* write the PHY register's value */
      XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
      
      if (pPrt->PhyType != SK_PHY_XMAC) {
            do {
                  XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
                  /* wait until 'Busy' is cleared */
            } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
      }
}     /* SkXmPhyWrite */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmPhyRead() - Read from GPHY register
 *
 * Description:   reads a 16-bit word from GPHY through MDIO
 *
 * Returns:
 *    nothing
 */
void SkGmPhyRead(
SK_AC *pAC,             /* Adapter Context */
SK_IOC      IoC,              /* I/O Context */
int         Port,             /* Port Index (MAC_1 + n) */
int         PhyReg,                 /* Register Address (Offset) */
SK_U16      SK_FAR *pVal)     /* Pointer to Value */
{
      SK_U16      Ctrl;
      SK_GEPORT   *pPrt;
#ifdef VCPU
      u_long SimCyle;
      u_long SimLowTime;
      
      VCPUgetTime(&SimCyle, &SimLowTime);
      VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
            PhyReg, SimCyle, SimLowTime);
#endif /* VCPU */
      
      pPrt = &pAC->GIni.GP[Port];
      
      /* set PHY-Register offset and 'Read' OpCode (= 1) */
      *pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) |
            GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD);

      GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);

      GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
      
      /* additional check for MDC/MDIO activity */
      if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
            *pVal = 0;
            return;
      }

      *pVal |= GM_SMI_CT_BUSY;
      
      do {
#ifdef VCPU
            VCPUwaitTime(1000);
#endif /* VCPU */

            GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);

      /* wait until 'ReadValid' is set */
      } while (Ctrl == *pVal);
      
      /* get the PHY register's value */
      GM_IN16(IoC, Port, GM_SMI_DATA, pVal);

#ifdef VCPU
      VCPUgetTime(&SimCyle, &SimLowTime);
      VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
            SimCyle, SimLowTime);
#endif /* VCPU */

}     /* SkGmPhyRead */


/******************************************************************************
 *
 *    SkGmPhyWrite() - Write to GPHY register
 *
 * Description:   writes a 16-bit word to GPHY through MDIO
 *
 * Returns:
 *    nothing
 */
void SkGmPhyWrite(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* I/O Context */
int         Port,       /* Port Index (MAC_1 + n) */
int         PhyReg,           /* Register Address (Offset) */
SK_U16      Val)        /* Value */
{
      SK_U16      Ctrl;
      SK_GEPORT   *pPrt;
#ifdef VCPU
      SK_U32      DWord;
      u_long      SimCyle;
      u_long      SimLowTime;
      
      VCPUgetTime(&SimCyle, &SimLowTime);
      VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
            PhyReg, Val, SimCyle, SimLowTime);
#endif /* VCPU */
      
      pPrt = &pAC->GIni.GP[Port];
      
      /* write the PHY register's value */
      GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
      
      /* set PHY-Register offset and 'Write' OpCode (= 0) */
      Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);

      GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);

      GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
      
      /* additional check for MDC/MDIO activity */
      if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
            return;
      }
      
      Val |= GM_SMI_CT_BUSY;

      do {
#ifdef VCPU
            /* read Timer value */
            SK_IN32(IoC, B2_TI_VAL, &DWord);

            VCPUwaitTime(1000);
#endif /* VCPU */

            GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);

      /* wait until 'Busy' is cleared */
      } while (Ctrl == Val);
      
#ifdef VCPU
      VCPUgetTime(&SimCyle, &SimLowTime);
      VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
            SimCyle, SimLowTime);
#endif /* VCPU */

}     /* SkGmPhyWrite */
#endif /* YUKON */


#ifdef SK_DIAG
/******************************************************************************
 *
 *    SkGePhyRead() - Read from PHY register
 *
 * Description:   calls a read PHY routine dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkGePhyRead(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* I/O Context */
int         Port,       /* Port Index (MAC_1 + n) */
int         PhyReg,           /* Register Address (Offset) */
SK_U16      *pVal)            /* Pointer to Value */
{
      void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);

      if (pAC->GIni.GIGenesis) {
            r_func = SkXmPhyRead;
      }
      else {
            r_func = SkGmPhyRead;
      }
      
      r_func(pAC, IoC, Port, PhyReg, pVal);
}     /* SkGePhyRead */


/******************************************************************************
 *
 *    SkGePhyWrite() - Write to PHY register
 *
 * Description:   calls a write PHY routine dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkGePhyWrite(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* I/O Context */
int         Port,       /* Port Index (MAC_1 + n) */
int         PhyReg,           /* Register Address (Offset) */
SK_U16      Val)        /* Value */
{
      void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);

      if (pAC->GIni.GIGenesis) {
            w_func = SkXmPhyWrite;
      }
      else {
            w_func = SkGmPhyWrite;
      }
      
      w_func(pAC, IoC, Port, PhyReg, Val);
}     /* SkGePhyWrite */
#endif /* SK_DIAG */


/******************************************************************************
 *
 *    SkMacPromiscMode() - Enable / Disable Promiscuous Mode
 *
 * Description:
 *   enables / disables promiscuous mode by setting Mode Register (XMAC) or
 *   Receive Control Register (GMAC) dep. on board type     
 *
 * Returns:
 *    nothing
 */
void SkMacPromiscMode(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port, /* Port Index (MAC_1 + n) */
SK_BOOL     Enable)     /* Enable / Disable */
{
#ifdef YUKON
      SK_U16      RcReg;
#endif
#ifdef GENESIS
      SK_U32      MdReg;
#endif      

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            XM_IN32(IoC, Port, XM_MODE, &MdReg);
            /* enable or disable promiscuous mode */
            if (Enable) {
                  MdReg |= XM_MD_ENA_PROM;
            }
            else {
                  MdReg &= ~XM_MD_ENA_PROM;
            }
            /* setup Mode Register */
            XM_OUT32(IoC, Port, XM_MODE, MdReg);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
            
            /* enable or disable unicast and multicast filtering */
            if (Enable) {
                  RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
            }
            else {
                  RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
            }
            /* setup Receive Control Register */
            GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
      }
#endif /* YUKON */

}     /* SkMacPromiscMode*/


/******************************************************************************
 *
 *    SkMacHashing() - Enable / Disable Hashing
 *
 * Description:
 *   enables / disables hashing by setting Mode Register (XMAC) or
 *   Receive Control Register (GMAC) dep. on board type           
 *
 * Returns:
 *    nothing
 */
void SkMacHashing(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port, /* Port Index (MAC_1 + n) */
SK_BOOL     Enable)     /* Enable / Disable */
{
#ifdef YUKON
      SK_U16      RcReg;
#endif      
#ifdef GENESIS
      SK_U32      MdReg;
#endif

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            XM_IN32(IoC, Port, XM_MODE, &MdReg);
            /* enable or disable hashing */
            if (Enable) {
                  MdReg |= XM_MD_ENA_HASH;
            }
            else {
                  MdReg &= ~XM_MD_ENA_HASH;
            }
            /* setup Mode Register */
            XM_OUT32(IoC, Port, XM_MODE, MdReg);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
            
            /* enable or disable multicast filtering */
            if (Enable) {
                  RcReg |= GM_RXCR_MCF_ENA;
            }
            else {
                  RcReg &= ~GM_RXCR_MCF_ENA;
            }
            /* setup Receive Control Register */
            GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
      }
#endif /* YUKON */

}     /* SkMacHashing*/


#ifdef SK_DIAG
/******************************************************************************
 *
 *    SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
 *
 * Description:
 *    The features
 *     - FCS stripping,                         SK_STRIP_FCS_ON/OFF
 *     - pad byte stripping,                    SK_STRIP_PAD_ON/OFF
 *     - don't set XMR_FS_ERR in status   SK_LENERR_OK_ON/OFF
 *       for inrange length error frames
 *     - don't set XMR_FS_ERR in status   SK_BIG_PK_OK_ON/OFF
 *       for frames > 1514 bytes
 *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
 *
 *    for incoming packets may be enabled/disabled by this function.
 *    Additional modes may be added later.
 *    Multiple modes can be enabled/disabled at the same time.
 *    The new configuration is written to the Rx Command register immediately.
 *
 * Returns:
 *    nothing
 */
static void SkXmSetRxCmd(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
int         Mode)       /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
                                 SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
{
      SK_U16      OldRxCmd;
      SK_U16      RxCmd;

      XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);

      RxCmd = OldRxCmd;
      
      switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
      case SK_STRIP_FCS_ON:
            RxCmd |= XM_RX_STRIP_FCS;
            break;
      case SK_STRIP_FCS_OFF:
            RxCmd &= ~XM_RX_STRIP_FCS;
            break;
      }

      switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
      case SK_STRIP_PAD_ON:
            RxCmd |= XM_RX_STRIP_PAD;
            break;
      case SK_STRIP_PAD_OFF:
            RxCmd &= ~XM_RX_STRIP_PAD;
            break;
      }

      switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
      case SK_LENERR_OK_ON:
            RxCmd |= XM_RX_LENERR_OK;
            break;
      case SK_LENERR_OK_OFF:
            RxCmd &= ~XM_RX_LENERR_OK;
            break;
      }

      switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
      case SK_BIG_PK_OK_ON:
            RxCmd |= XM_RX_BIG_PK_OK;
            break;
      case SK_BIG_PK_OK_OFF:
            RxCmd &= ~XM_RX_BIG_PK_OK;
            break;
      }

      switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
      case SK_SELF_RX_ON:
            RxCmd |= XM_RX_SELF_RX;
            break;
      case SK_SELF_RX_OFF:
            RxCmd &= ~XM_RX_SELF_RX;
            break;
      }

      /* Write the new mode to the Rx command register if required */
      if (OldRxCmd != RxCmd) {
            XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
      }
}     /* SkXmSetRxCmd */


/******************************************************************************
 *
 *    SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
 *
 * Description:
 *    The features
 *     - FCS (CRC) stripping,                   SK_STRIP_FCS_ON/OFF
 *     - don't set GMR_FS_LONG_ERR        SK_BIG_PK_OK_ON/OFF
 *       for frames > 1514 bytes
 *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
 *
 *    for incoming packets may be enabled/disabled by this function.
 *    Additional modes may be added later.
 *    Multiple modes can be enabled/disabled at the same time.
 *    The new configuration is written to the Rx Command register immediately.
 *
 * Returns:
 *    nothing
 */
static void SkGmSetRxCmd(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
int         Mode)       /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
                                 SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
{
      SK_U16      OldRxCmd;
      SK_U16      RxCmd;

      if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
            
            GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);

            RxCmd = OldRxCmd;

            if ((Mode & SK_STRIP_FCS_ON) != 0) {
                  RxCmd |= GM_RXCR_CRC_DIS;
            }
            else {
                  RxCmd &= ~GM_RXCR_CRC_DIS;
            }
            /* Write the new mode to the Rx control register if required */
            if (OldRxCmd != RxCmd) {
                  GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
            }
      }

      if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
            
            GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);

            RxCmd = OldRxCmd;

            if ((Mode & SK_BIG_PK_OK_ON) != 0) {
                  RxCmd |= GM_SMOD_JUMBO_ENA;
            }
            else {
                  RxCmd &= ~GM_SMOD_JUMBO_ENA;
            }
            /* Write the new mode to the Rx control register if required */
            if (OldRxCmd != RxCmd) {
                  GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
            }
      }
}     /* SkGmSetRxCmd */


/******************************************************************************
 *
 *    SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
 *
 * Description:   modifies the MAC's Rx Control reg. dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkMacSetRxCmd(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
int         Mode)       /* Rx Mode */
{
      if (pAC->GIni.GIGenesis) {
            
            SkXmSetRxCmd(pAC, IoC, Port, Mode);
      }
      else {
            
            SkGmSetRxCmd(pAC, IoC, Port, Mode);
      }

}     /* SkMacSetRxCmd */


/******************************************************************************
 *
 *    SkMacCrcGener() - Enable / Disable CRC Generation
 *
 * Description:   enables / disables CRC generation dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkMacCrcGener(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port, /* Port Index (MAC_1 + n) */
SK_BOOL     Enable)     /* Enable / Disable */
{
      SK_U16      Word;

      if (pAC->GIni.GIGenesis) {
            
            XM_IN16(IoC, Port, XM_TX_CMD, &Word);

            if (Enable) {
                  Word &= ~XM_TX_NO_CRC;
            }
            else {
                  Word |= XM_TX_NO_CRC;
            }
            /* setup Tx Command Register */
            XM_OUT16(IoC, Port, XM_TX_CMD, Word);
      }
      else {
            
            GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
            
            if (Enable) {
                  Word &= ~GM_TXCR_CRC_DIS;
            }
            else {
                  Word |= GM_TXCR_CRC_DIS;
            }
            /* setup Tx Control Register */
            GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
      }

}     /* SkMacCrcGener*/

#endif /* SK_DIAG */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmClrExactAddr() - Clear Exact Match Address Registers
 *
 * Description:
 *    All Exact Match Address registers of the XMAC 'Port' will be
 *    cleared starting with 'StartNum' up to (and including) the
 *    Exact Match address number of 'StopNum'.
 *
 * Returns:
 *    nothing
 */
void SkXmClrExactAddr(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
int         StartNum,   /* Begin with this Address Register Index (0..15) */
int         StopNum)    /* Stop after finished with this Register Idx (0..15) */
{
      int         i;
      SK_U16      ZeroAddr[3] = {0x0000, 0x0000, 0x0000};

      if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
            StartNum > StopNum) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
            return;
      }

      for (i = StartNum; i <= StopNum; i++) {
            XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
      }
}     /* SkXmClrExactAddr */
#endif /* GENESIS */


/******************************************************************************
 *
 *    SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
 *
 * Description:
 *    Flush the transmit FIFO of the MAC specified by the index 'Port'
 *
 * Returns:
 *    nothing
 */
void SkMacFlushTxFifo(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
#ifdef GENESIS
      SK_U32      MdReg;

      if (pAC->GIni.GIGenesis) {
            
            XM_IN32(IoC, Port, XM_MODE, &MdReg);

            XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            /* no way to flush the FIFO we have to issue a reset */
            /* TBD */
      }
#endif /* YUKON */

}     /* SkMacFlushTxFifo */


/******************************************************************************
 *
 *    SkMacFlushRxFifo() - Flush the MAC's receive FIFO
 *
 * Description:
 *    Flush the receive FIFO of the MAC specified by the index 'Port'
 *
 * Returns:
 *    nothing
 */
static void SkMacFlushRxFifo(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
#ifdef GENESIS
      SK_U32      MdReg;

      if (pAC->GIni.GIGenesis) {

            XM_IN32(IoC, Port, XM_MODE, &MdReg);

            XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            /* no way to flush the FIFO we have to issue a reset */
            /* TBD */
      }
#endif /* YUKON */

}     /* SkMacFlushRxFifo */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmSoftRst() - Do a XMAC software reset
 *
 * Description:
 *    The PHY registers should not be destroyed during this
 *    kind of software reset. Therefore the XMAC Software Reset
 *    (XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
 *
 *    The software reset is done by
 *          - disabling the Rx and Tx state machine,
 *          - resetting the statistics module,
 *          - clear all other significant XMAC Mode,
 *            Command, and Control Registers
 *          - clearing the Hash Register and the
 *            Exact Match Address registers, and
 *          - flushing the XMAC's Rx and Tx FIFOs.
 *
 * Note:
 *    Another requirement when stopping the XMAC is to
 *    avoid sending corrupted frames on the network.
 *    Disabling the Tx state machine will NOT interrupt
 *    the currently transmitted frame. But we must take care
 *    that the Tx FIFO is cleared AFTER the current frame
 *    is complete sent to the network.
 *
 *    It takes about 12ns to send a frame with 1538 bytes.
 *    One PCI clock goes at least 15ns (66MHz). Therefore
 *    after reading XM_GP_PORT back, we are sure that the
 *    transmitter is disabled AND idle. And this means
 *    we may flush the transmit FIFO now.
 *
 * Returns:
 *    nothing
 */
static void SkXmSoftRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U16      ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
      
      /* reset the statistics module */
      XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);

      /* disable all XMAC IRQs */
      XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
      
      XM_OUT32(IoC, Port, XM_MODE, 0);          /* clear Mode Reg */
      
      XM_OUT16(IoC, Port, XM_TX_CMD, 0);        /* reset TX CMD Reg */
      XM_OUT16(IoC, Port, XM_RX_CMD, 0);        /* reset RX CMD Reg */
      
      /* disable all PHY IRQs */
      switch (pAC->GIni.GP[Port].PhyType) {
      case SK_PHY_BCOM:
                  SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
                  break;
#ifdef OTHER_PHY
            case SK_PHY_LONE:
                  SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
                  break;
            case SK_PHY_NAT:
                  /* todo: National
                   SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
                  break;
#endif /* OTHER_PHY */
      }

      /* clear the Hash Register */
      XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);

      /* clear the Exact Match Address registers */
      SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
      
      /* clear the Source Check Address registers */
      XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);

}     /* SkXmSoftRst */


/******************************************************************************
 *
 *    SkXmHardRst() - Do a XMAC hardware reset
 *
 * Description:
 *    The XMAC of the specified 'Port' and all connected devices
 *    (PHY and SERDES) will receive a reset signal on its *Reset pins.
 *    External PHYs must be reset by clearing a bit in the GPIO register
 *  (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns).
 *
 * ATTENTION:
 *    It is absolutely necessary to reset the SW_RST Bit first
 *    before calling this function.
 *
 * Returns:
 *    nothing
 */
static void SkXmHardRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U32      Reg;
      int         i;
      int         TOut;
      SK_U16      Word;

      for (i = 0; i < 4; i++) {
            /* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
            SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);

            TOut = 0;
            do {
                  if (TOut++ > 10000) {
                        /*
                         * Adapter seems to be in RESET state.
                         * Registers cannot be written.
                         */
                        return;
                  }

                  SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
                  
                  SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
            
            } while ((Word & MFF_SET_MAC_RST) == 0);
      }

      /* For external PHYs there must be special handling */
      if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
            
            SK_IN32(IoC, B2_GP_IO, &Reg);
            
            if (Port == 0) {
                  Reg |= GP_DIR_0;  /* set to output */
                  Reg &= ~GP_IO_0;  /* set PHY reset (active low) */
            }
            else {
                  Reg |= GP_DIR_2;  /* set to output */
                  Reg &= ~GP_IO_2;  /* set PHY reset (active low) */
            }
            /* reset external PHY */
            SK_OUT32(IoC, B2_GP_IO, Reg);

            /* short delay */
            SK_IN32(IoC, B2_GP_IO, &Reg);
      }
}     /* SkXmHardRst */


/******************************************************************************
 *
 *    SkXmClearRst() - Release the PHY & XMAC reset
 *
 * Description:
 *
 * Returns:
 *    nothing
 */
static void SkXmClearRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U32      DWord;
      
      /* clear HW reset */
      SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);

      if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {

            SK_IN32(IoC, B2_GP_IO, &DWord);

            if (Port == 0) {
                  DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */
            }
            else {
                  DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */
            }
            /* Clear PHY reset */
            SK_OUT32(IoC, B2_GP_IO, DWord);

            /* Enable GMII interface */
            XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
      }
}     /* SkXmClearRst */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmSoftRst() - Do a GMAC software reset
 *
 * Description:
 *    The GPHY registers should not be destroyed during this
 *    kind of software reset.
 *
 * Returns:
 *    nothing
 */
static void SkGmSoftRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U16      EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
      SK_U16  RxCtrl;

      /* reset the statistics module */

      /* disable all GMAC IRQs */
      SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
      
      /* disable all PHY IRQs */
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
      
      /* clear the Hash Register */
      GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash);

      /* Enable Unicast and Multicast filtering */
      GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
      
      GM_OUT16(IoC, Port, GM_RX_CTRL,
            (SK_U16)(RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA));

}     /* SkGmSoftRst */


/******************************************************************************
 *
 *    SkGmHardRst() - Do a GMAC hardware reset
 *
 * Description:
 *
 * Returns:
 *    nothing
 */
static void SkGmHardRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U32      DWord;
      
      /* WA code for COMA mode */
      if (pAC->GIni.GIYukonLite &&
            pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
            
            SK_IN32(IoC, B2_GP_IO, &DWord);

            DWord |= (GP_DIR_9 | GP_IO_9);

            /* set PHY reset */
            SK_OUT32(IoC, B2_GP_IO, DWord);
      }

      /* set GPHY Control reset */
      SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);

      /* set GMAC Control reset */
      SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);

}     /* SkGmHardRst */


/******************************************************************************
 *
 *    SkGmClearRst() - Release the GPHY & GMAC reset
 *
 * Description:
 *
 * Returns:
 *    nothing
 */
static void SkGmClearRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_U32      DWord;
      
#ifdef XXX
            /* clear GMAC Control reset */
            SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);

            /* set GMAC Control reset */
            SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
#endif /* XXX */

      /* WA code for COMA mode */
      if (pAC->GIni.GIYukonLite &&
            pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
            
            SK_IN32(IoC, B2_GP_IO, &DWord);

            DWord |= GP_DIR_9;            /* set to output */
            DWord &= ~GP_IO_9;            /* clear PHY reset (active high) */

            /* clear PHY reset */
            SK_OUT32(IoC, B2_GP_IO, DWord);
      }

      /* set HWCFG_MODE */
      DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
            GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
            (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
            GPC_HWCFG_GMII_FIB);

      /* set GPHY Control reset */
      SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);

      /* release GPHY Control reset */
      SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);

#ifdef VCPU
      VCpuWait(9000);
#endif /* VCPU */

      /* clear GMAC Control reset */
      SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);

#ifdef VCPU
      VCpuWait(2000);
      
      SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord);
                  
      SK_IN32(IoC, B0_ISRC, &DWord);
#endif /* VCPU */

}     /* SkGmClearRst */
#endif /* YUKON */


/******************************************************************************
 *
 *    SkMacSoftRst() - Do a MAC software reset
 *
 * Description:   calls a MAC software reset routine dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkMacSoftRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];

      /* disable receiver and transmitter */
      SkMacRxTxDisable(pAC, IoC, Port);

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            SkXmSoftRst(pAC, IoC, Port);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            SkGmSoftRst(pAC, IoC, Port);
      }
#endif /* YUKON */

      /* flush the MAC's Rx and Tx FIFOs */
      SkMacFlushTxFifo(pAC, IoC, Port);
      
      SkMacFlushRxFifo(pAC, IoC, Port);

      pPrt->PState = SK_PRT_STOP;

}     /* SkMacSoftRst */


/******************************************************************************
 *
 *    SkMacHardRst() - Do a MAC hardware reset
 *
 * Description:   calls a MAC hardware reset routine dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkMacHardRst(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port) /* Port Index (MAC_1 + n) */
{
      
#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            SkXmHardRst(pAC, IoC, Port);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            SkGmHardRst(pAC, IoC, Port);
      }
#endif /* YUKON */

      pAC->GIni.GP[Port].PState = SK_PRT_RESET;

}     /* SkMacHardRst */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmInitMac() - Initialize the XMAC II
 *
 * Description:
 *    Initialize the XMAC of the specified port.
 *    The XMAC must be reset or stopped before calling this function.
 *
 * Note:
 *    The XMAC's Rx and Tx state machine is still disabled when returning.
 *
 * Returns:
 *    nothing
 */
void SkXmInitMac(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      int               i;
      SK_U16            SWord;

      pPrt = &pAC->GIni.GP[Port];

      if (pPrt->PState == SK_PRT_STOP) {
            /* Port State: SK_PRT_STOP */
            /* Verify that the reset bit is cleared */
            SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);

            if ((SWord & MFF_SET_MAC_RST) != 0) {
                  /* PState does not match HW state */
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
                  /* Correct it */
                  pPrt->PState = SK_PRT_RESET;
            }
      }

      if (pPrt->PState == SK_PRT_RESET) {

            SkXmClearRst(pAC, IoC, Port);

            if (pPrt->PhyType != SK_PHY_XMAC) {
                  /* read Id from external PHY (all have the same address) */
                  SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);

                  /*
                   * Optimize MDIO transfer by suppressing preamble.
                   * Must be done AFTER first access to BCOM chip.
                   */
                  XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
                  
                  XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);

                  if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
                        /*
                         * Workaround BCOM Errata for the C0 type.
                         * Write magic patterns to reserved registers.
                         */
                        i = 0;
                        while (BcomRegC0Hack[i].PhyReg != 0) {
                              SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
                                    BcomRegC0Hack[i].PhyVal);
                              i++;
                        }
                  }
                  else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
                        /*
                         * Workaround BCOM Errata for the A1 type.
                         * Write magic patterns to reserved registers.
                         */
                        i = 0;
                        while (BcomRegA1Hack[i].PhyReg != 0) {
                              SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
                                    BcomRegA1Hack[i].PhyVal);
                              i++;
                        }
                  }

                  /*
                   * Workaround BCOM Errata (#10523) for all BCom PHYs.
                   * Disable Power Management after reset.
                   */
                  SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
                  
                  SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
                        (SK_U16)(SWord | PHY_B_AC_DIS_PM));

                  /* PHY LED initialization is done in SkGeXmitLED() */
            }

            /* Dummy read the Interrupt source register */
            XM_IN16(IoC, Port, XM_ISRC, &SWord);
            
            /*
             * The auto-negotiation process starts immediately after
             * clearing the reset. The auto-negotiation process should be
             * started by the SIRQ, therefore stop it here immediately.
             */
            SkMacInitPhy(pAC, IoC, Port, SK_FALSE);

#ifdef TEST_ONLY
            /* temp. code: enable signal detect */
            /* WARNING: do not override GMII setting above */
            XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG);
#endif
      }

      /*
       * configure the XMACs Station Address
       * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
       * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
       */
      for (i = 0; i < 3; i++) {
            /*
             * The following 2 statements are together endianess
             * independent. Remember this when changing.
             */
            SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
            
            XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
      }

      /* Tx Inter Packet Gap (XM_TX_IPG): use default */
      /* Tx High Water Mark (XM_TX_HI_WM):      use default */
      /* Tx Low Water Mark (XM_TX_LO_WM): use default */
      /* Host Request Threshold (XM_HT_THR):    use default */
      /* Rx Request Threshold (XM_RX_THR):      use default */
      /* Rx Low Water Mark (XM_RX_LO_WM): use default */

      /* configure Rx High Water Mark (XM_RX_HI_WM) */
      XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM);

      /* Configure Tx Request Threshold */
      SWord = SK_XM_THR_SL;                     /* for single port */

      if (pAC->GIni.GIMacsFound > 1) {
            switch (pAC->GIni.GIPortUsage) {
            case SK_RED_LINK:
                  SWord = SK_XM_THR_REDL;       /* redundant link */
                  break;
            case SK_MUL_LINK:
                  SWord = SK_XM_THR_MULL;       /* load balancing */
                  break;
            case SK_JUMBO_LINK:
                  SWord = SK_XM_THR_JUMBO;      /* jumbo frames */
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
                  break;
            }
      }
      XM_OUT16(IoC, Port, XM_TX_THR, SWord);

      /* setup register defaults for the Tx Command Register */
      XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);

      /* setup register defaults for the Rx Command Register */
      SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;

      if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
            SWord |= XM_RX_BIG_PK_OK;
      }

      if (pPrt->PLinkMode == SK_LMODE_HALF) {
            /*
             * If in manual half duplex mode the other side might be in
             * full duplex mode, so ignore if a carrier extension is not seen
             * on frames received
             */
            SWord |= XM_RX_DIS_CEXT;
      }
      
      XM_OUT16(IoC, Port, XM_RX_CMD, SWord);

      /*
       * setup register defaults for the Mode Register
       *    - Don't strip error frames to avoid Store & Forward
       *      on the Rx side.
       *    - Enable 'Check Station Address' bit
       *    - Enable 'Check Address Array' bit
       */
      XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);

      /*
       * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
       *    - Enable all bits excepting 'Octets Rx OK Low CntOv'
       *      and 'Octets Rx OK Hi Cnt Ov'.
       */
      XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);

      /*
       * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
       *    - Enable all bits excepting 'Octets Tx OK Low CntOv'
       *      and 'Octets Tx OK Hi Cnt Ov'.
       */
      XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);

      /*
       * Do NOT init XMAC interrupt mask here.
       * All interrupts remain disable until link comes up!
       */

      /*
       * Any additional configuration changes may be done now.
       * The last action is to enable the Rx and Tx state machine.
       * This should be done after the auto-negotiation process
       * has been completed successfully.
       */
}     /* SkXmInitMac */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmInitMac() - Initialize the GMAC
 *
 * Description:
 *    Initialize the GMAC of the specified port.
 *    The GMAC must be reset or stopped before calling this function.
 *
 * Note:
 *    The GMAC's Rx and Tx state machine is still disabled when returning.
 *
 * Returns:
 *    nothing
 */
void SkGmInitMac(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      int               i;
      SK_U16            SWord;
      SK_U32            DWord;

      pPrt = &pAC->GIni.GP[Port];

      if (pPrt->PState == SK_PRT_STOP) {
            /* Port State: SK_PRT_STOP */
            /* Verify that the reset bit is cleared */
            SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
            
            if ((DWord & GMC_RST_SET) != 0) {
                  /* PState does not match HW state */
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
                  /* Correct it */
                  pPrt->PState = SK_PRT_RESET;
            }
      }

      if (pPrt->PState == SK_PRT_RESET) {
            
            SkGmHardRst(pAC, IoC, Port);

            SkGmClearRst(pAC, IoC, Port);
            
            /* Auto-negotiation ? */
            if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
                  /* Auto-negotiation disabled */

                  /* get General Purpose Control */
                  GM_IN16(IoC, Port, GM_GP_CTRL, &SWord);

                  /* disable auto-update for speed, duplex and flow-control */
                  SWord |= GM_GPCR_AU_ALL_DIS;
                  
                  /* setup General Purpose Control Register */
                  GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
                  
                  SWord = GM_GPCR_AU_ALL_DIS;
            }
            else {
                  SWord = 0;
            }

            /* speed settings */
            switch (pPrt->PLinkSpeed) {
            case SK_LSPEED_AUTO:
            case SK_LSPEED_1000MBPS:
                  SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100;
                  break;
            case SK_LSPEED_100MBPS:
                  SWord |= GM_GPCR_SPEED_100;
                  break;
            case SK_LSPEED_10MBPS:
                  break;
            }

            /* duplex settings */
            if (pPrt->PLinkMode != SK_LMODE_HALF) {
                  /* set full duplex */
                  SWord |= GM_GPCR_DUP_FULL;
            }

            /* flow-control settings */
            switch (pPrt->PFlowCtrlMode) {
            case SK_FLOW_MODE_NONE:
                  /* set Pause Off */
                  SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF);
                  /* disable Tx & Rx flow-control */
                  SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
                  break;
            case SK_FLOW_MODE_LOC_SEND:
                  /* disable Rx flow-control */
                  SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
                  break;
            case SK_FLOW_MODE_SYMMETRIC:
            case SK_FLOW_MODE_SYM_OR_REM:
                  /* enable Tx & Rx flow-control */
                  break;
            }

            /* setup General Purpose Control Register */
            GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);

            /* dummy read the Interrupt Source Register */
            SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
            
#ifndef VCPU
            /* read Id from PHY */
            SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
            
            SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
#endif /* VCPU */
      }

      (void)SkGmResetCounter(pAC, IoC, Port);

      /* setup Transmit Control Register */
      GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres));

      /* setup Receive Control Register */
      GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
            GM_RXCR_CRC_DIS);

      /* setup Transmit Flow Control Register */
      GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);

      /* setup Transmit Parameter Register */
#ifdef VCPU
      GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
#endif /* VCPU */

    SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) |
                  TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) |
                  TX_IPG_JAM_DATA(pPrt->PMacJamIpgData);
      
      GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);

      /* configure the Serial Mode Register */
#ifdef VCPU
      GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
#endif /* VCPU */
      
      SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData);

      if (pPrt->PMacLimit4) {
            /* reset of collision counter after 4 consecutive collisions */
            SWord |= GM_SMOD_LIMIT_4;
      }

      if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
            /* enable jumbo mode (Max. Frame Length = 9018) */
            SWord |= GM_SMOD_JUMBO_ENA;
      }
      
      GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
      
      /*
       * configure the GMACs Station Addresses
       * in PROM you can find our addresses at:
       * B2_MAC_1 = xx xx xx xx xx x0 virtual address
       * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
       * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
       */

      for (i = 0; i < 3; i++) {
            /*
             * The following 2 statements are together endianess
             * independent. Remember this when changing.
             */
            /* physical address: will be used for pause frames */
            SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);

#ifdef WA_DEV_16
            /* WA for deviation #16 */
            if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) {
                  /* swap the address bytes */
                  SWord = ((SWord & 0xff00) >> 8)     | ((SWord & 0x00ff) << 8);

                  /* write to register in reversed order */
                  GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
            }
            else {
                  GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
            }
#else       
            GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
#endif /* WA_DEV_16 */
            
            /* virtual address: will be used for data */
            SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);

            GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
            
            /* reset Multicast filtering Hash registers 1-3 */
            GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0);
      }

      /* reset Multicast filtering Hash register 4 */
      GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);

      /* enable interrupt mask for counter overflows */
      GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
      GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
      GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);

#if defined(SK_DIAG) || defined(DEBUG)
      /* read General Purpose Status */
      GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
      
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("MAC Stat Reg.=0x%04X\n", SWord));
#endif /* SK_DIAG || DEBUG */

#ifdef SK_DIAG
      c_print("MAC Stat Reg=0x%04X\n", SWord);
#endif /* SK_DIAG */

}     /* SkGmInitMac */
#endif /* YUKON */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmInitDupMd() - Initialize the XMACs Duplex Mode
 *
 * Description:
 *    This function initializes the XMACs Duplex Mode.
 *    It should be called after successfully finishing
 *    the Auto-negotiation Process
 *
 * Returns:
 *    nothing
 */
static void SkXmInitDupMd(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      switch (pAC->GIni.GP[Port].PLinkModeStatus) {
      case SK_LMODE_STAT_AUTOHALF:
      case SK_LMODE_STAT_HALF:
            /* Configuration Actions for Half Duplex Mode */
            /*
             * XM_BURST = default value. We are probable not quick
             *    enough at the 'XMAC' bus to burst 8kB.
             *    The XMAC stops bursting if no transmit frames
             *    are available or the burst limit is exceeded.
             */
            /* XM_TX_RT_LIM = default value (15) */
            /* XM_TX_STIME = default value (0xff = 4096 bit times) */
            break;
      case SK_LMODE_STAT_AUTOFULL:
      case SK_LMODE_STAT_FULL:
            /* Configuration Actions for Full Duplex Mode */
            /*
             * The duplex mode is configured by the PHY,
             * therefore it seems to be that there is nothing
             * to do here.
             */
            break;
      case SK_LMODE_STAT_UNKNOWN:
      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
            break;
      }
}     /* SkXmInitDupMd */


/******************************************************************************
 *
 *    SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
 *
 * Description:
 *    This function initializes the Pause Mode which should
 *    be used for this port.
 *    It should be called after successfully finishing
 *    the Auto-negotiation Process
 *
 * Returns:
 *    nothing
 */
static void SkXmInitPauseMd(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U32            DWord;
      SK_U16            Word;

      pPrt = &pAC->GIni.GP[Port];

      XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
      
      if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
            pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {

            /* Disable Pause Frame Reception */
            Word |= XM_MMU_IGN_PF;
      }
      else {
            /*
             * enabling pause frame reception is required for 1000BT
             * because the XMAC is not reset if the link is going down
             */
            /* Enable Pause Frame Reception */
            Word &= ~XM_MMU_IGN_PF;
      }     
      
      XM_OUT16(IoC, Port, XM_MMU_CMD, Word);

      XM_IN32(IoC, Port, XM_MODE, &DWord);

      if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
            pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {

            /*
             * Configure Pause Frame Generation
             * Use internal and external Pause Frame Generation.
             * Sending pause frames is edge triggered.
             * Send a Pause frame with the maximum pause time if
             * internal oder external FIFO full condition occurs.
             * Send a zero pause time frame to re-start transmission.
             */

            /* XM_PAUSE_DA = '010000C28001' (default) */

            /* XM_MAC_PTIME = 0xffff (maximum) */
            /* remember this value is defined in big endian (!) */
            XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);

            /* Set Pause Mode in Mode Register */
            DWord |= XM_PAUSE_MODE;

            /* Set Pause Mode in MAC Rx FIFO */
            SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
      }
      else {
            /*
             * disable pause frame generation is required for 1000BT
             * because the XMAC is not reset if the link is going down
             */
            /* Disable Pause Mode in Mode Register */
            DWord &= ~XM_PAUSE_MODE;

            /* Disable Pause Mode in MAC Rx FIFO */
            SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
      }
      
      XM_OUT32(IoC, Port, XM_MODE, DWord);
}     /* SkXmInitPauseMd*/


/******************************************************************************
 *
 *    SkXmInitPhyXmac() - Initialize the XMAC Phy registers
 *
 * Description:   initializes all the XMACs Phy registers
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkXmInitPhyXmac(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
      SK_GEPORT   *pPrt;
      SK_U16            Ctrl;

      pPrt = &pAC->GIni.GP[Port];
      Ctrl = 0;
      
      /* Auto-negotiation ? */
      if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyXmac: no auto-negotiation Port %d\n", Port));
            /* Set DuplexMode in Config register */
            if (pPrt->PLinkMode == SK_LMODE_FULL) {
                  Ctrl |= PHY_CT_DUP_MD;
            }

            /*
             * Do NOT enable Auto-negotiation here. This would hold
             * the link down because no IDLEs are transmitted
             */
      }
      else {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyXmac: with auto-negotiation Port %d\n", Port));
            /* Set Auto-negotiation advertisement */

            /* Set Full/half duplex capabilities */
            switch (pPrt->PLinkMode) {
            case SK_LMODE_AUTOHALF:
                  Ctrl |= PHY_X_AN_HD;
                  break;
            case SK_LMODE_AUTOFULL:
                  Ctrl |= PHY_X_AN_FD;
                  break;
            case SK_LMODE_AUTOBOTH:
                  Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
                        SKERR_HWI_E015MSG);
            }

            /* Set Flow-control capabilities */
            switch (pPrt->PFlowCtrlMode) {
            case SK_FLOW_MODE_NONE:
                  Ctrl |= PHY_X_P_NO_PAUSE;
                  break;
            case SK_FLOW_MODE_LOC_SEND:
                  Ctrl |= PHY_X_P_ASYM_MD;
                  break;
            case SK_FLOW_MODE_SYMMETRIC:
                  Ctrl |= PHY_X_P_SYM_MD;
                  break;
            case SK_FLOW_MODE_SYM_OR_REM:
                  Ctrl |= PHY_X_P_BOTH_MD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                        SKERR_HWI_E016MSG);
            }

            /* Write AutoNeg Advertisement Register */
            SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);

            /* Restart Auto-negotiation */
            Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
      }

      if (DoLoop) {
            /* Set the Phy Loopback bit, too */
            Ctrl |= PHY_CT_LOOP;
      }

      /* Write to the Phy control register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
}     /* SkXmInitPhyXmac */


/******************************************************************************
 *
 *    SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
 *
 * Description:   initializes all the Broadcom Phy registers
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkXmInitPhyBcom(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
      SK_GEPORT   *pPrt;
      SK_U16            Ctrl1;
      SK_U16            Ctrl2;
      SK_U16            Ctrl3;
      SK_U16            Ctrl4;
      SK_U16            Ctrl5;

      Ctrl1 = PHY_CT_SP1000;
      Ctrl2 = 0;
      Ctrl3 = PHY_SEL_TYPE;
      Ctrl4 = PHY_B_PEC_EN_LTR;
      Ctrl5 = PHY_B_AC_TX_TST;

      pPrt = &pAC->GIni.GP[Port];

      /* manually Master/Slave ? */
      if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
            Ctrl2 |= PHY_B_1000C_MSE;
            
            if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
                  Ctrl2 |= PHY_B_1000C_MSC;
            }
      }
      /* Auto-negotiation ? */
      if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyBcom: no auto-negotiation Port %d\n", Port));
            /* Set DuplexMode in Config register */
            if (pPrt->PLinkMode == SK_LMODE_FULL) {
                  Ctrl1 |= PHY_CT_DUP_MD;
            }

            /* Determine Master/Slave manually if not already done */
            if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
                  Ctrl2 |= PHY_B_1000C_MSE;     /* set it to Slave */
            }

            /*
             * Do NOT enable Auto-negotiation here. This would hold
             * the link down because no IDLES are transmitted
             */
      }
      else {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyBcom: with auto-negotiation Port %d\n", Port));
            /* Set Auto-negotiation advertisement */

            /*
             * Workaround BCOM Errata #1 for the C5 type.
             * 1000Base-T Link Acquisition Failure in Slave Mode
             * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
             */
            Ctrl2 |= PHY_B_1000C_RD;
            
             /* Set Full/half duplex capabilities */
            switch (pPrt->PLinkMode) {
            case SK_LMODE_AUTOHALF:
                  Ctrl2 |= PHY_B_1000C_AHD;
                  break;
            case SK_LMODE_AUTOFULL:
                  Ctrl2 |= PHY_B_1000C_AFD;
                  break;
            case SK_LMODE_AUTOBOTH:
                  Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
                        SKERR_HWI_E015MSG);
            }

            /* Set Flow-control capabilities */
            switch (pPrt->PFlowCtrlMode) {
            case SK_FLOW_MODE_NONE:
                  Ctrl3 |= PHY_B_P_NO_PAUSE;
                  break;
            case SK_FLOW_MODE_LOC_SEND:
                  Ctrl3 |= PHY_B_P_ASYM_MD;
                  break;
            case SK_FLOW_MODE_SYMMETRIC:
                  Ctrl3 |= PHY_B_P_SYM_MD;
                  break;
            case SK_FLOW_MODE_SYM_OR_REM:
                  Ctrl3 |= PHY_B_P_BOTH_MD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                        SKERR_HWI_E016MSG);
            }

            /* Restart Auto-negotiation */
            Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
      }
      
      /* Initialize LED register here? */
      /* No. Please do it in SkDgXmitLed() (if required) and swap
         init order of LEDs and XMAC. (MAl) */
      
      /* Write 1000Base-T Control Register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
      
      /* Write AutoNeg Advertisement Register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
      
      if (DoLoop) {
            /* Set the Phy Loopback bit, too */
            Ctrl1 |= PHY_CT_LOOP;
      }

      if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
            /* configure FIFO to high latency for transmission of ext. packets */
            Ctrl4 |= PHY_B_PEC_HIGH_LA;

            /* configure reception of extended packets */
            Ctrl5 |= PHY_B_AC_LONG_PACK;

            SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
      }

      /* Configure LED Traffic Mode and Jumbo Frame usage if specified */
      SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
      
      /* Write to the Phy control register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Control Reg=0x%04X\n", Ctrl1));
}     /* SkXmInitPhyBcom */
#endif /* GENESIS */

#ifdef YUKON
/******************************************************************************
 *
 *    SkGmInitPhyMarv() - Initialize the Marvell Phy registers
 *
 * Description:   initializes all the Marvell Phy registers
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkGmInitPhyMarv(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
      SK_GEPORT   *pPrt;
      SK_U16            PhyCtrl;
      SK_U16            C1000BaseT;
      SK_U16            AutoNegAdv;
      SK_U16            ExtPhyCtrl;
      SK_U16            LedCtrl;
      SK_BOOL           AutoNeg;
#if defined(SK_DIAG) || defined(DEBUG)
      SK_U16            PhyStat;
      SK_U16            PhyStat1;
      SK_U16            PhySpecStat;
#endif /* SK_DIAG || DEBUG */

      pPrt = &pAC->GIni.GP[Port];

      /* Auto-negotiation ? */
      if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
            AutoNeg = SK_FALSE;
      }
      else {
            AutoNeg = SK_TRUE;
      }
      
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("InitPhyMarv: Port %d, auto-negotiation %s\n",
             Port, AutoNeg ? "ON" : "OFF"));

#ifdef VCPU
      VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
            Port, DoLoop);
#else /* VCPU */
      if (DoLoop) {
            /* Set 'MAC Power up'-bit, set Manual MDI configuration */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
                  PHY_M_PC_MAC_POW_UP);
      }
      else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) {
            /* Read Ext. PHY Specific Control */
            SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
            
            ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
                  PHY_M_EC_MAC_S_MSK);
            
            ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ) |
                  PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
      
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
      }

      /* Read PHY Control */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);

      if (!AutoNeg) {
            /* Disable Auto-negotiation */
            PhyCtrl &= ~PHY_CT_ANE;
      }

      PhyCtrl |= PHY_CT_RESET;
      /* Assert software reset */
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
#endif /* VCPU */

      PhyCtrl = 0 /* PHY_CT_COL_TST */;
      C1000BaseT = 0;
      AutoNegAdv = PHY_SEL_TYPE;

      /* manually Master/Slave ? */
      if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
            /* enable Manual Master/Slave */
            C1000BaseT |= PHY_M_1000C_MSE;
            
            if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
                  C1000BaseT |= PHY_M_1000C_MSC;      /* set it to Master */
            }
      }
      
      /* Auto-negotiation ? */
      if (!AutoNeg) {
            
            if (pPrt->PLinkMode == SK_LMODE_FULL) {
                  /* Set Full Duplex Mode */
                  PhyCtrl |= PHY_CT_DUP_MD;
            }

            /* Set Master/Slave manually if not already done */
            if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
                  C1000BaseT |= PHY_M_1000C_MSE;      /* set it to Slave */
            }

            /* Set Speed */
            switch (pPrt->PLinkSpeed) {
            case SK_LSPEED_AUTO:
            case SK_LSPEED_1000MBPS:
                  PhyCtrl |= PHY_CT_SP1000;
                  break;
            case SK_LSPEED_100MBPS:
                  PhyCtrl |= PHY_CT_SP100;
                  break;
            case SK_LSPEED_10MBPS:
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
                        SKERR_HWI_E019MSG);
            }

            if (!DoLoop) {
                  PhyCtrl |= PHY_CT_RESET;
            }
      }
      else {
            /* Set Auto-negotiation advertisement */
            
            if (pAC->GIni.GICopperType) {
                  /* Set Speed capabilities */
                  switch (pPrt->PLinkSpeed) {
                  case SK_LSPEED_AUTO:
                        C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
                        AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
                              PHY_M_AN_10_FD | PHY_M_AN_10_HD;
                        break;
                  case SK_LSPEED_1000MBPS:
                        C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
                        break;
                  case SK_LSPEED_100MBPS:
                        AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
                              /* advertise 10Base-T also */
                              PHY_M_AN_10_FD | PHY_M_AN_10_HD;
                        break;
                  case SK_LSPEED_10MBPS:
                        AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
                        break;
                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
                              SKERR_HWI_E019MSG);
                  }

                  /* Set Full/half duplex capabilities */
                  switch (pPrt->PLinkMode) {
                  case SK_LMODE_AUTOHALF:
                        C1000BaseT &= ~PHY_M_1000C_AFD;
                        AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
                        break;
                  case SK_LMODE_AUTOFULL:
                        C1000BaseT &= ~PHY_M_1000C_AHD;
                        AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
                        break;
                  case SK_LMODE_AUTOBOTH:
                        break;
                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
                              SKERR_HWI_E015MSG);
                  }
                  
                  /* Set Flow-control capabilities */
                  switch (pPrt->PFlowCtrlMode) {
                  case SK_FLOW_MODE_NONE:
                        AutoNegAdv |= PHY_B_P_NO_PAUSE;
                        break;
                  case SK_FLOW_MODE_LOC_SEND:
                        AutoNegAdv |= PHY_B_P_ASYM_MD;
                        break;
                  case SK_FLOW_MODE_SYMMETRIC:
                        AutoNegAdv |= PHY_B_P_SYM_MD;
                        break;
                  case SK_FLOW_MODE_SYM_OR_REM:
                        AutoNegAdv |= PHY_B_P_BOTH_MD;
                        break;
                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                              SKERR_HWI_E016MSG);
                  }
            }
            else {      /* special defines for FIBER (88E1011S only) */
                  
                  /* Set Full/half duplex capabilities */
                  switch (pPrt->PLinkMode) {
                  case SK_LMODE_AUTOHALF:
                        AutoNegAdv |= PHY_M_AN_1000X_AHD;
                        break;
                  case SK_LMODE_AUTOFULL:
                        AutoNegAdv |= PHY_M_AN_1000X_AFD;
                        break;
                  case SK_LMODE_AUTOBOTH:
                        AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
                        break;
                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
                              SKERR_HWI_E015MSG);
                  }
                  
                  /* Set Flow-control capabilities */
                  switch (pPrt->PFlowCtrlMode) {
                  case SK_FLOW_MODE_NONE:
                        AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
                        break;
                  case SK_FLOW_MODE_LOC_SEND:
                        AutoNegAdv |= PHY_M_P_ASYM_MD_X;
                        break;
                  case SK_FLOW_MODE_SYMMETRIC:
                        AutoNegAdv |= PHY_M_P_SYM_MD_X;
                        break;
                  case SK_FLOW_MODE_SYM_OR_REM:
                        AutoNegAdv |= PHY_M_P_BOTH_MD_X;
                        break;
                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                              SKERR_HWI_E016MSG);
                  }
            }

            if (!DoLoop) {
                  /* Restart Auto-negotiation */
                  PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
            }
      }
      
#ifdef VCPU
      /*
       * E-mail from Gu Lin (08-03-2002):
       */
      
      /* Program PHY register 30 as 16'h0708 for simulation speed up */
      SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */);
      
      VCpuWait(2000);

#else /* VCPU */
      
      /* Write 1000Base-T Control Register */
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT));
      
      /* Write AutoNeg Advertisement Register */
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
#endif /* VCPU */
      
      if (DoLoop) {
            /* Set the PHY Loopback bit */
            PhyCtrl |= PHY_CT_LOOP;

#ifdef XXX
            /* Program PHY register 16 as 16'h0400 to force link good */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
#endif /* XXX */

#ifndef VCPU
            if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
                  /* Write Ext. PHY Specific Control */
                  SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
                        (SK_U16)((pPrt->PLinkSpeed + 2) << 4));
            }
#endif /* VCPU */
      }
#ifdef TEST_ONLY
      else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
                  /* Write PHY Specific Control */
                  SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
                        PHY_M_PC_EN_DET_MSK);
      }
#endif

      /* Write to the PHY Control register */
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl));

#ifdef VCPU
      VCpuWait(2000);
#else

      LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS);

      if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) {
            LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL;
      }

      if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) {
            LedCtrl |= PHY_M_LEDC_DP_CTRL;
      }
      
      SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl);

      if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) {
            /* only in forced 100 Mbps mode */
            if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) {

                  SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER,
                        PHY_M_LED_MO_100(MO_LED_ON));
            }
      }

#ifdef SK_DIAG
      c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl);
      c_print("Set 1000 B-T=0x%04X\n", C1000BaseT);
      c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv);
      c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl);
#endif /* SK_DIAG */

#if defined(SK_DIAG) || defined(DEBUG)
      /* Read PHY Control */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
      
      /* Read 1000Base-T Control Register */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("1000B-T Ctrl =0x%04X\n", C1000BaseT));
      
      /* Read AutoNeg Advertisement Register */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
      
      /* Read Ext. PHY Specific Control */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
      
      /* Read PHY Status */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Stat Reg.=0x%04X\n", PhyStat));
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Stat Reg.=0x%04X\n", PhyStat1));
      
      /* Read PHY Specific Status */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Spec Stat=0x%04X\n", PhySpecStat));
#endif /* SK_DIAG || DEBUG */

#ifdef SK_DIAG
      c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
      c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
      c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
      c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
      c_print("PHY Stat Reg=0x%04X\n", PhyStat);
      c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
      c_print("PHY Spec Reg=0x%04X\n", PhySpecStat);
#endif /* SK_DIAG */

#endif /* VCPU */

}     /* SkGmInitPhyMarv */
#endif /* YUKON */


#ifdef OTHER_PHY
/******************************************************************************
 *
 *    SkXmInitPhyLone() - Initialize the Level One Phy registers
 *
 * Description:   initializes all the Level One Phy registers
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkXmInitPhyLone(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
      SK_GEPORT   *pPrt;
      SK_U16            Ctrl1;
      SK_U16            Ctrl2;
      SK_U16            Ctrl3;

      Ctrl1 = PHY_CT_SP1000;
      Ctrl2 = 0;
      Ctrl3 = PHY_SEL_TYPE;

      pPrt = &pAC->GIni.GP[Port];

      /* manually Master/Slave ? */
      if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
            Ctrl2 |= PHY_L_1000C_MSE;
            
            if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
                  Ctrl2 |= PHY_L_1000C_MSC;
            }
      }
      /* Auto-negotiation ? */
      if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
            /*
             * level one spec say: "1000 Mbps: manual mode not allowed"
             * but lets see what happens...
             */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyLone: no auto-negotiation Port %d\n", Port));
            /* Set DuplexMode in Config register */
            if (pPrt->PLinkMode == SK_LMODE_FULL) {
                  Ctrl1 |= PHY_CT_DUP_MD;
            }

            /* Determine Master/Slave manually if not already done */
            if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
                  Ctrl2 |= PHY_L_1000C_MSE;     /* set it to Slave */
            }

            /*
             * Do NOT enable Auto-negotiation here. This would hold
             * the link down because no IDLES are transmitted
             */
      }
      else {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("InitPhyLone: with auto-negotiation Port %d\n", Port));
            /* Set Auto-negotiation advertisement */

            /* Set Full/half duplex capabilities */
            switch (pPrt->PLinkMode) {
            case SK_LMODE_AUTOHALF:
                  Ctrl2 |= PHY_L_1000C_AHD;
                  break;
            case SK_LMODE_AUTOFULL:
                  Ctrl2 |= PHY_L_1000C_AFD;
                  break;
            case SK_LMODE_AUTOBOTH:
                  Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
                        SKERR_HWI_E015MSG);
            }

            /* Set Flow-control capabilities */
            switch (pPrt->PFlowCtrlMode) {
            case SK_FLOW_MODE_NONE:
                  Ctrl3 |= PHY_L_P_NO_PAUSE;
                  break;
            case SK_FLOW_MODE_LOC_SEND:
                  Ctrl3 |= PHY_L_P_ASYM_MD;
                  break;
            case SK_FLOW_MODE_SYMMETRIC:
                  Ctrl3 |= PHY_L_P_SYM_MD;
                  break;
            case SK_FLOW_MODE_SYM_OR_REM:
                  Ctrl3 |= PHY_L_P_BOTH_MD;
                  break;
            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                        SKERR_HWI_E016MSG);
            }

            /* Restart Auto-negotiation */
            Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
      }
      
      /* Write 1000Base-T Control Register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
      
      /* Write AutoNeg Advertisement Register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));

      if (DoLoop) {
            /* Set the Phy Loopback bit, too */
            Ctrl1 |= PHY_CT_LOOP;
      }

      /* Write to the Phy control register */
      SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Control Reg=0x%04X\n", Ctrl1));
}     /* SkXmInitPhyLone */


/******************************************************************************
 *
 *    SkXmInitPhyNat() - Initialize the National Phy registers
 *
 * Description:   initializes all the National Phy registers
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkXmInitPhyNat(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
/* todo: National */
}     /* SkXmInitPhyNat */
#endif /* OTHER_PHY */


/******************************************************************************
 *
 *    SkMacInitPhy() - Initialize the PHY registers
 *
 * Description:   calls the Init PHY routines dep. on board type
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
void SkMacInitPhy(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     DoLoop)           /* Should a Phy LoopBack be set-up? */
{
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            switch (pPrt->PhyType) {
            case SK_PHY_XMAC:
                  SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
                  break;
            case SK_PHY_BCOM:
                  SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
                  break;
#ifdef OTHER_PHY
            case SK_PHY_LONE:
                  SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
                  break;
            case SK_PHY_NAT:
                  SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
                  break;
#endif /* OTHER_PHY */
            }
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
      }
#endif /* YUKON */

}     /* SkMacInitPhy */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmAutoNegDoneXmac() - Auto-negotiation handling
 *
 * Description:
 *    This function handles the auto-negotiation if the Done bit is set.
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
static int SkXmAutoNegDoneXmac(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            ResAb;            /* Resolved Ability */
      SK_U16            LPAb;       /* Link Partner Ability */

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("AutoNegDoneXmac, Port %d\n", Port));

      pPrt = &pAC->GIni.GP[Port];

      /* Get PHY parameters */
      SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
      SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);

      if ((LPAb & PHY_X_AN_RFB) != 0) {
            /* At least one of the remote fault bit is set */
            /* Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Remote fault bit set Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_OTHER);
      }

      /* Check Duplex mismatch */
      if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
      }
      else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
      }
      else {
            /* Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_DUP_CAP);
      }

      /* Check PAUSE mismatch */
      /* We are NOT using chapter 4.23 of the Xaqti manual */
      /* We are using IEEE 802.3z/D5.0 Table 37-4 */
      if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
           pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
          (LPAb & PHY_X_P_SYM_MD) != 0) {
            /* Symmetric PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
      }
      else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
               (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
            /* Enable PAUSE receive, disable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
      }
      else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
               (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
            /* Disable PAUSE receive, enable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
      }
      else {
            /* PAUSE mismatch -> no PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
      }
      pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;

      return(SK_AND_OK);
}     /* SkXmAutoNegDoneXmac */


/******************************************************************************
 *
 *    SkXmAutoNegDoneBcom() - Auto-negotiation handling
 *
 * Description:
 *    This function handles the auto-negotiation if the Done bit is set.
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
static int SkXmAutoNegDoneBcom(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            LPAb;       /* Link Partner Ability */
      SK_U16            AuxStat;    /* Auxiliary Status */

#ifdef TEST_ONLY
01-Sep-2000 RA;:;:
      SK_U16            ResAb;            /* Resolved Ability */
#endif      /* 0 */

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("AutoNegDoneBcom, Port %d\n", Port));
      pPrt = &pAC->GIni.GP[Port];

      /* Get PHY parameters */
      SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
#ifdef TEST_ONLY
01-Sep-2000 RA;:;:
      SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
#endif      /* 0 */
      
      SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);

      if ((LPAb & PHY_B_AN_RF) != 0) {
            /* Remote fault bit is set: Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Remote fault bit set Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_OTHER);
      }

      /* Check Duplex mismatch */
      if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
      }
      else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
      }
      else {
            /* Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_DUP_CAP);
      }
      
#ifdef TEST_ONLY
01-Sep-2000 RA;:;:
      /* Check Master/Slave resolution */
      if ((ResAb & PHY_B_1000S_MSF) != 0) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("Master/Slave Fault Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            pPrt->PMSStatus = SK_MS_STAT_FAULT;
            return(SK_AND_OTHER);
      }
      
      pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
            SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
#endif      /* 0 */

      /* Check PAUSE mismatch ??? */
      /* We are using IEEE 802.3z/D5.0 Table 37-4 */
      if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
            /* Symmetric PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
      }
      else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
            /* Enable PAUSE receive, disable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
      }
      else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) {
            /* Disable PAUSE receive, enable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
      }
      else {
            /* PAUSE mismatch -> no PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
      }
      pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;

      return(SK_AND_OK);
}     /* SkXmAutoNegDoneBcom */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmAutoNegDoneMarv() - Auto-negotiation handling
 *
 * Description:
 *    This function handles the auto-negotiation if the Done bit is set.
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
static int SkGmAutoNegDoneMarv(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            LPAb;       /* Link Partner Ability */
      SK_U16            ResAb;            /* Resolved Ability */
      SK_U16            AuxStat;    /* Auxiliary Status */

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("AutoNegDoneMarv, Port %d\n", Port));
      pPrt = &pAC->GIni.GP[Port];

      /* Get PHY parameters */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("Link P.Abil.=0x%04X\n", LPAb));
      
      if ((LPAb & PHY_M_AN_RF) != 0) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Remote fault bit set Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_OTHER);
      }

      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
      
      /* Check Master/Slave resolution */
      if ((ResAb & PHY_B_1000S_MSF) != 0) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("Master/Slave Fault Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            pPrt->PMSStatus = SK_MS_STAT_FAULT;
            return(SK_AND_OTHER);
      }
      
      pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
            (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
      
      /* Read PHY Specific Status */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
      
      /* Check Speed & Duplex resolved */
      if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
            return(SK_AND_DUP_CAP);
      }
      
      if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
      }
      else {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
      }
      
      /* Check PAUSE mismatch ??? */
      /* We are using IEEE 802.3z/D5.0 Table 37-4 */
      if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
            /* Symmetric PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
      }
      else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
            /* Enable PAUSE receive, disable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
      }
      else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
            /* Disable PAUSE receive, enable PAUSE transmit */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
      }
      else {
            /* PAUSE mismatch -> no PAUSE */
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
      }
      
      /* set used link speed */
      switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
      case (unsigned)PHY_M_PS_SPEED_1000:
            pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
            break;
      case PHY_M_PS_SPEED_100:
            pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
            break;
      default:
            pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
      }

      return(SK_AND_OK);
}     /* SkGmAutoNegDoneMarv */
#endif /* YUKON */


#ifdef OTHER_PHY
/******************************************************************************
 *
 *    SkXmAutoNegDoneLone() - Auto-negotiation handling
 *
 * Description:
 *    This function handles the auto-negotiation if the Done bit is set.
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
static int SkXmAutoNegDoneLone(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            ResAb;            /* Resolved Ability */
      SK_U16            LPAb;       /* Link Partner Ability */
      SK_U16            QuickStat;  /* Auxiliary Status */

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("AutoNegDoneLone, Port %d\n", Port));
      pPrt = &pAC->GIni.GP[Port];

      /* Get PHY parameters */
      SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
      SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
      SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);

      if ((LPAb & PHY_L_AN_RF) != 0) {
            /* Remote fault bit is set */
            /* Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegFail: Remote fault bit set Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            return(SK_AND_OTHER);
      }

      /* Check Duplex mismatch */
      if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
      }
      else {
            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
      }
      
      /* Check Master/Slave resolution */
      if ((ResAb & PHY_L_1000S_MSF) != 0) {
            /* Error */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("Master/Slave Fault Port %d\n", Port));
            pPrt->PAutoNegFail = SK_TRUE;
            pPrt->PMSStatus = SK_MS_STAT_FAULT;
            return(SK_AND_OTHER);
      }
      else if (ResAb & PHY_L_1000S_MSR) {
            pPrt->PMSStatus = SK_MS_STAT_MASTER;
      }
      else {
            pPrt->PMSStatus = SK_MS_STAT_SLAVE;
      }

      /* Check PAUSE mismatch */
      /* We are using IEEE 802.3z/D5.0 Table 37-4 */
      /* we must manually resolve the abilities here */
      pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
      
      switch (pPrt->PFlowCtrlMode) {
      case SK_FLOW_MODE_NONE:
            /* default */
            break;
      case SK_FLOW_MODE_LOC_SEND:
            if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
                  (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
                  /* Disable PAUSE receive, enable PAUSE transmit */
                  pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
            }
            break;
      case SK_FLOW_MODE_SYMMETRIC:
            if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
                  /* Symmetric PAUSE */
                  pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
            }
            break;
      case SK_FLOW_MODE_SYM_OR_REM:
            if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
                  PHY_L_QS_AS_PAUSE) {
                  /* Enable PAUSE receive, disable PAUSE transmit */
                  pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
            }
            else if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
                  /* Symmetric PAUSE */
                  pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
            }
            break;
      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
                  SKERR_HWI_E016MSG);
      }
      
      return(SK_AND_OK);
}     /* SkXmAutoNegDoneLone */


/******************************************************************************
 *
 *    SkXmAutoNegDoneNat() - Auto-negotiation handling
 *
 * Description:
 *    This function handles the auto-negotiation if the Done bit is set.
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
static int SkXmAutoNegDoneNat(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
/* todo: National */
      return(SK_AND_OK);
}     /* SkXmAutoNegDoneNat */
#endif /* OTHER_PHY */


/******************************************************************************
 *
 *    SkMacAutoNegDone() - Auto-negotiation handling
 *
 * Description:   calls the auto-negotiation done routines dep. on board type
 *
 * Returns:
 *    SK_AND_OK   o.k.
 *    SK_AND_DUP_CAP    Duplex capability error happened
 *    SK_AND_OTHER      Other error happened
 */
int   SkMacAutoNegDone(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      int   Rtv;

      Rtv = SK_AND_OK;

      pPrt = &pAC->GIni.GP[Port];

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            switch (pPrt->PhyType) {
            
            case SK_PHY_XMAC:
                  Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
                  break;
            case SK_PHY_BCOM:
                  Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
                  break;
#ifdef OTHER_PHY
            case SK_PHY_LONE:
                  Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
                  break;
            case SK_PHY_NAT:
                  Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
                  break;
#endif /* OTHER_PHY */
            default:
                  return(SK_AND_OTHER);
            }
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
      }
#endif /* YUKON */
      
      if (Rtv != SK_AND_OK) {
            return(Rtv);
      }

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("AutoNeg done Port %d\n", Port));
      
      /* We checked everything and may now enable the link */
      pPrt->PAutoNegFail = SK_FALSE;

      SkMacRxTxEnable(pAC, IoC, Port);
      
      return(SK_AND_OK);
}     /* SkMacAutoNegDone */


/******************************************************************************
 *
 *    SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
 *
 * Description:   enables Rx/Tx dep. on board type
 *
 * Returns:
 *    0     o.k.
 *    != 0  Error happened
 */
int SkMacRxTxEnable(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            Reg;        /* 16-bit register value */
      SK_U16            IntMask;    /* MAC interrupt mask */
#ifdef GENESIS
      SK_U16            SWord;
#endif

      pPrt = &pAC->GIni.GP[Port];

      if (!pPrt->PHWLinkUp) {
            /* The Hardware link is NOT up */
            return(0);
      }

      if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
           pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
           pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
           pPrt->PAutoNegFail) {
            /* Auto-negotiation is not done or failed */
            return(0);
      }

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            /* set Duplex Mode and Pause Mode */
            SkXmInitDupMd(pAC, IoC, Port);
            
            SkXmInitPauseMd(pAC, IoC, Port);
      
            /*
             * Initialize the Interrupt Mask Register. Default IRQs are...
             *    - Link Asynchronous Event
             *    - Link Partner requests config
             *    - Auto Negotiation Done
             *    - Rx Counter Event Overflow
             *    - Tx Counter Event Overflow
             *    - Transmit FIFO Underrun
             */
            IntMask = XM_DEF_MSK;

#ifdef DEBUG
            /* add IRQ for Receive FIFO Overflow */
            IntMask &= ~XM_IS_RXF_OV;
#endif /* DEBUG */
            
            if (pPrt->PhyType != SK_PHY_XMAC) {
                  /* disable GP0 interrupt bit */
                  IntMask |= XM_IS_INP_ASS;
            }
            XM_OUT16(IoC, Port, XM_IMSK, IntMask);
      
            /* get MMU Command Reg. */
            XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
            
            if (pPrt->PhyType != SK_PHY_XMAC &&
                  (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
                   pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
                  /* set to Full Duplex */
                  Reg |= XM_MMU_GMII_FD;
            }
            
            switch (pPrt->PhyType) {
            case SK_PHY_BCOM:
                  /*
                   * Workaround BCOM Errata (#10523) for all BCom Phys
                   * Enable Power Management after link up
                   */
                  SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
                  SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
                        (SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
            SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK,
                        (SK_U16)PHY_B_DEF_MSK);
                  break;
#ifdef OTHER_PHY
            case SK_PHY_LONE:
                  SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
                  break;
            case SK_PHY_NAT:
                  /* todo National:
                  SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
                  /* no interrupts possible from National ??? */
                  break;
#endif /* OTHER_PHY */
            }
            
            /* enable Rx/Tx */
            XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            /*
             * Initialize the Interrupt Mask Register. Default IRQs are...
             *    - Rx Counter Event Overflow
             *    - Tx Counter Event Overflow
             *    - Transmit FIFO Underrun
             */
            IntMask = GMAC_DEF_MSK;

#ifdef DEBUG
            /* add IRQ for Receive FIFO Overrun */
            IntMask |= GM_IS_RX_FF_OR;
#endif /* DEBUG */
            
            SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
            
            /* get General Purpose Control */
            GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
            
            if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
                  pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
                  /* set to Full Duplex */
                  Reg |= GM_GPCR_DUP_FULL;
            }
            
            /* enable Rx/Tx */
        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA |
                  GM_GPCR_TX_ENA));

#ifndef VCPU
            /* Enable all PHY interrupts */
        SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK,
                  (SK_U16)PHY_M_DEF_MSK);
#endif /* VCPU */
      }
#endif /* YUKON */
                              
      return(0);

}     /* SkMacRxTxEnable */


/******************************************************************************
 *
 *    SkMacRxTxDisable() - Disable Receiver and Transmitter
 *
 * Description:   disables Rx/Tx dep. on board type
 *
 * Returns: N/A
 */
void SkMacRxTxDisable(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_U16      Word;

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
            
            XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
      
            /* dummy read to ensure writing */
            XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            
            GM_IN16(IoC, Port, GM_GP_CTRL, &Word);

        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA |
                  GM_GPCR_TX_ENA)));

            /* dummy read to ensure writing */
            GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
      }
#endif /* YUKON */

}     /* SkMacRxTxDisable */


/******************************************************************************
 *
 *    SkMacIrqDisable() - Disable IRQ from MAC
 *
 * Description:   sets the IRQ-mask to disable IRQ dep. on board type
 *
 * Returns: N/A
 */
void SkMacIrqDisable(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
#ifdef GENESIS
      SK_U16            Word;
#endif

      pPrt = &pAC->GIni.GP[Port];

#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            
            /* disable all XMAC IRQs */
            XM_OUT16(IoC, Port, XM_IMSK, 0xffff);     
            
            /* Disable all PHY interrupts */
            switch (pPrt->PhyType) {
                  case SK_PHY_BCOM:
                        /* Make sure that PHY is initialized */
                        if (pPrt->PState != SK_PRT_RESET) {
                              /* NOT allowed if BCOM is in RESET state */
                              /* Workaround BCOM Errata (#10523) all BCom */
                              /* Disable Power Management if link is down */
                              SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
                              SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
                                    (SK_U16)(Word | PHY_B_AC_DIS_PM));
                              SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
                        }
                        break;
#ifdef OTHER_PHY
                  case SK_PHY_LONE:
                        SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
                        break;
                  case SK_PHY_NAT:
                        /* todo: National
                        SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
                        break;
#endif /* OTHER_PHY */
            }
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            /* disable all GMAC IRQs */
            SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
            
#ifndef VCPU
            /* Disable all PHY interrupts */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
#endif /* VCPU */
      }
#endif /* YUKON */

}     /* SkMacIrqDisable */


#ifdef SK_DIAG
/******************************************************************************
 *
 *    SkXmSendCont() - Enable / Disable Send Continuous Mode
 *
 * Description:   enable / disable Send Continuous Mode on XMAC
 *
 * Returns:
 *    nothing
 */
void SkXmSendCont(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port, /* Port Index (MAC_1 + n) */
SK_BOOL     Enable)     /* Enable / Disable */
{
      SK_U32      MdReg;

      XM_IN32(IoC, Port, XM_MODE, &MdReg);

      if (Enable) {
            MdReg |= XM_MD_TX_CONT;
      }
      else {
            MdReg &= ~XM_MD_TX_CONT;
      }
      /* setup Mode Register */
      XM_OUT32(IoC, Port, XM_MODE, MdReg);

}     /* SkXmSendCont */


/******************************************************************************
 *
 *    SkMacTimeStamp() - Enable / Disable Time Stamp
 *
 * Description:   enable / disable Time Stamp generation for Rx packets
 *
 * Returns:
 *    nothing
 */
void SkMacTimeStamp(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* IO context */
int         Port, /* Port Index (MAC_1 + n) */
SK_BOOL     Enable)     /* Enable / Disable */
{
      SK_U32      MdReg;
      SK_U8 TimeCtrl;

      if (pAC->GIni.GIGenesis) {

            XM_IN32(IoC, Port, XM_MODE, &MdReg);

            if (Enable) {
                  MdReg |= XM_MD_ATS;
            }
            else {
                  MdReg &= ~XM_MD_ATS;
            }
            /* setup Mode Register */
            XM_OUT32(IoC, Port, XM_MODE, MdReg);
      }
      else {
            if (Enable) {
                  TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
            }
            else {
                  TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
            }
            /* Start/Stop Time Stamp Timer */
            SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl);
      }

}     /* SkMacTimeStamp*/

#else /* !SK_DIAG */

#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
 *
 *    This function analyses the Interrupt status word. If any of the
 *    Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable
 *    is set true.
 */
void SkXmAutoNegLipaXmac(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_U16      IStatus)    /* Interrupt Status word to analyse */
{
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];

      if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
            (IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) {

            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04X\n",
                  Port, IStatus));
            pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
      }
}     /* SkXmAutoNegLipaXmac */
#endif /* GENESIS */


/******************************************************************************
 *
 *    SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
 *
 *    This function analyses the PHY status word.
 *  If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
 *    is set true.
 */
void SkMacAutoNegLipaPhy(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_U16      PhyStat)    /* PHY Status word to analyse */
{
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];

      if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
            (PhyStat & PHY_ST_AN_OVER) != 0) {

            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04X\n",
                  Port, PhyStat));
            pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
      }
}     /* SkMacAutoNegLipaPhy */


#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmIrq() - Interrupt Service Routine
 *
 * Description:   services an Interrupt Request of the XMAC
 *
 * Note:
 *    With an external PHY, some interrupt bits are not meaningfull any more:
 *    - LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
 *    - LinkPartnerReqConfig (bit #10)    XM_IS_LIPA_RC
 *    - Page Received (bit #9)            XM_IS_RX_PAGE
 *    - NextPageLoadedForXmt (bit #8)           XM_IS_TX_PAGE
 *    - AutoNegDone (bit #7)              XM_IS_AND
 *    Also probably not valid any more is the GP0 input bit:
 *    - GPRegisterBit0set                 XM_IS_INP_ASS
 *
 * Returns:
 *    nothing
 */
static void SkXmIrq(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_EVPARA   Para;
      SK_U16            IStatus;    /* Interrupt status read from the XMAC */
      SK_U16            IStatus2;
#ifdef SK_SLIM
    SK_U64      OverflowStatus;
#endif      

      pPrt = &pAC->GIni.GP[Port];
      
      XM_IN16(IoC, Port, XM_ISRC, &IStatus);
      
      /* LinkPartner Auto-negable? */
      if (pPrt->PhyType == SK_PHY_XMAC) {
            SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
      }
      else {
            /* mask bits that are not used with ext. PHY */
            IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
                  XM_IS_RX_PAGE | XM_IS_TX_PAGE |
                  XM_IS_AND | XM_IS_INP_ASS);
      }
      
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
            ("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus));

      if (!pPrt->PHWLinkUp) {
            /* Spurious XMAC interrupt */
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
                  ("SkXmIrq: spurious interrupt on Port %d\n", Port));
            return;
      }

      if ((IStatus & XM_IS_INP_ASS) != 0) {
            /* Reread ISR Register if link is not in sync */
            XM_IN16(IoC, Port, XM_ISRC, &IStatus2);

            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
                  ("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n",
                   Port, IStatus, IStatus2));
            IStatus &= ~XM_IS_INP_ASS;
            IStatus |= IStatus2;
      }

      if ((IStatus & XM_IS_LNK_AE) != 0) {
            /* not used, GP0 is used instead */
      }

      if ((IStatus & XM_IS_TX_ABORT) != 0) {
            /* not used */
      }

      if ((IStatus & XM_IS_FRC_INT) != 0) {
            /* not used, use ASIC IRQ instead if needed */
      }

      if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
            SkHWLinkDown(pAC, IoC, Port);

            /* Signal to RLMT */
            Para.Para32[0] = (SK_U32)Port;
            SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);

            /* Start workaround Errata #2 timer */
            SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
                  SKGE_HWAC, SK_HWEV_WATIM, Para);
      }

      if ((IStatus & XM_IS_RX_PAGE) != 0) {
            /* not used */
      }

      if ((IStatus & XM_IS_TX_PAGE) != 0) {
            /* not used */
      }

      if ((IStatus & XM_IS_AND) != 0) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
                  ("SkXmIrq: AND on link that is up Port %d\n", Port));
      }

      if ((IStatus & XM_IS_TSC_OV) != 0) {
            /* not used */
      }

      /* Combined Tx & Rx Counter Overflow SIRQ Event */
      if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
#ifdef SK_SLIM
            SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
#else
            Para.Para32[0] = (SK_U32)Port;
            Para.Para32[1] = (SK_U32)IStatus;
            SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
#endif /* SK_SLIM */
      }

      if ((IStatus & XM_IS_RXF_OV) != 0) {
            /* normal situation -> no effect */
#ifdef DEBUG
            pPrt->PRxOverCnt++;
#endif /* DEBUG */
      }

      if ((IStatus & XM_IS_TXF_UR) != 0) {
            /* may NOT happen -> error log */
            SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
      }

      if ((IStatus & XM_IS_TX_COMP) != 0) {
            /* not served here */
      }

      if ((IStatus & XM_IS_RX_COMP) != 0) {
            /* not served here */
      }
}     /* SkXmIrq */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmIrq() - Interrupt Service Routine
 *
 * Description:   services an Interrupt Request of the GMAC
 *
 * Note:
 *
 * Returns:
 *    nothing
 */
static void SkGmIrq(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U8       IStatus;    /* Interrupt status */
#ifdef SK_SLIM
    SK_U64      OverflowStatus;
#else
      SK_EVPARA   Para;
#endif      

      pPrt = &pAC->GIni.GP[Port];
      
      SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
      
#ifdef XXX
      /* LinkPartner Auto-negable? */
      SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
#endif /* XXX */
      
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
            ("GmacIrq Port %d Isr 0x%04X\n", Port, IStatus));

      /* Combined Tx & Rx Counter Overflow SIRQ Event */
      if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
            /* these IRQs will be cleared by reading GMACs register */
#ifdef SK_SLIM
        SkGmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
#else
            Para.Para32[0] = (SK_U32)Port;
            Para.Para32[1] = (SK_U32)IStatus;
            SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
#endif            
      }

      if (IStatus & GM_IS_RX_FF_OR) {
            /* clear GMAC Rx FIFO Overrun IRQ */
            SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
#ifdef DEBUG
            pPrt->PRxOverCnt++;
#endif /* DEBUG */
      }

      if (IStatus & GM_IS_TX_FF_UR) {
            /* clear GMAC Tx FIFO Underrun IRQ */
            SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
            /* may NOT happen -> error log */
            SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
      }

      if (IStatus & GM_IS_TX_COMPL) {
            /* not served here */
      }

      if (IStatus & GM_IS_RX_COMPL) {
            /* not served here */
      }
}     /* SkGmIrq */
#endif /* YUKON */


/******************************************************************************
 *
 *    SkMacIrq() - Interrupt Service Routine for MAC
 *
 * Description:   calls the Interrupt Service Routine dep. on board type
 *
 * Returns:
 *    nothing
 */
void SkMacIrq(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
#ifdef GENESIS
      if (pAC->GIni.GIGenesis) {
            /* IRQ from XMAC */
            SkXmIrq(pAC, IoC, Port);
      }
#endif /* GENESIS */
      
#ifdef YUKON
      if (pAC->GIni.GIYukon) {
            /* IRQ from GMAC */
            SkGmIrq(pAC, IoC, Port);
      }
#endif /* YUKON */

}     /* SkMacIrq */

#endif /* !SK_DIAG */

#ifdef GENESIS
/******************************************************************************
 *
 *    SkXmUpdateStats() - Force the XMAC to output the current statistic
 *
 * Description:
 *    The XMAC holds its statistic internally. To obtain the current
 *    values a command must be sent so that the statistic data will
 *    be written to a predefined memory area on the adapter.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkXmUpdateStats(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
unsigned int Port)      /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U16            StatReg;
      int               WaitIndex;

      pPrt = &pAC->GIni.GP[Port];
      WaitIndex = 0;

      /* Send an update command to XMAC specified */
      XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);

      /*
       * It is an auto-clearing register. If the command bits
       * went to zero again, the statistics are transferred.
       * Normally the command should be executed immediately.
       * But just to be sure we execute a loop.
       */
      do {

            XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
            
            if (++WaitIndex > 10) {

                  SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);

                  return(1);
            }
      } while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
      
      return(0);
}     /* SkXmUpdateStats */


/******************************************************************************
 *
 *    SkXmMacStatistic() - Get XMAC counter value
 *
 * Description:
 *    Gets the 32bit counter value. Except for the octet counters
 *    the lower 32bit are counted in hardware and the upper 32bit
 *    must be counted in software by monitoring counter overflow interrupts.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkXmMacStatistic(
SK_AC *pAC,             /* adapter context */
SK_IOC      IoC,              /* IO context */
unsigned int Port,            /* Port Index (MAC_1 + n) */
SK_U16      StatAddr,         /* MIB counter base address */
SK_U32      SK_FAR *pVal)     /* ptr to return statistic value */
{
      if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
            
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
            
            return(1);
      }
      
      XM_IN32(IoC, Port, StatAddr, pVal);

      return(0);
}     /* SkXmMacStatistic */


/******************************************************************************
 *
 *    SkXmResetCounter() - Clear MAC statistic counter
 *
 * Description:
 *    Force the XMAC to clear its statistic counter.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkXmResetCounter(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
unsigned int Port)      /* Port Index (MAC_1 + n) */
{
      XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
      /* Clear two times according to Errata #3 */
      XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);

      return(0);
}     /* SkXmResetCounter */


/******************************************************************************
 *
 *    SkXmOverflowStatus() - Gets the status of counter overflow interrupt
 *
 * Description:
 *    Checks the source causing an counter overflow interrupt. On success the
 *    resulting counter overflow status is written to <pStatus>, whereas the
 *    upper dword stores the XMAC ReceiveCounterEvent register and the lower
 *    dword the XMAC TransmitCounterEvent register.
 *
 * Note:
 *    For XMAC the interrupt source is a self-clearing register, so the source
 *    must be checked only once. SIRQ module does another check to be sure
 *    that no interrupt get lost during process time.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkXmOverflowStatus(
SK_AC *pAC,                   /* adapter context */
SK_IOC      IoC,                    /* IO context */
unsigned int Port,                  /* Port Index (MAC_1 + n) */
SK_U16      IStatus,                /* Interupt Status from MAC */
SK_U64      SK_FAR *pStatus)  /* ptr for return overflow status value */
{
      SK_U64      Status;     /* Overflow status */
      SK_U32      RegVal;

      Status = 0;

      if ((IStatus & XM_IS_RXC_OV) != 0) {

            XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
            Status |= (SK_U64)RegVal << 32;
      }
      
      if ((IStatus & XM_IS_TXC_OV) != 0) {

            XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
            Status |= (SK_U64)RegVal;
      }

      *pStatus = Status;

      return(0);
}     /* SkXmOverflowStatus */
#endif /* GENESIS */


#ifdef YUKON
/******************************************************************************
 *
 *    SkGmUpdateStats() - Force the GMAC to output the current statistic
 *
 * Description:
 *    Empty function for GMAC. Statistic data is accessible in direct way.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkGmUpdateStats(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
unsigned int Port)      /* Port Index (MAC_1 + n) */
{
      return(0);
}


/******************************************************************************
 *
 *    SkGmMacStatistic() - Get GMAC counter value
 *
 * Description:
 *    Gets the 32bit counter value. Except for the octet counters
 *    the lower 32bit are counted in hardware and the upper 32bit
 *    must be counted in software by monitoring counter overflow interrupts.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkGmMacStatistic(
SK_AC *pAC,             /* adapter context */
SK_IOC      IoC,              /* IO context */
unsigned int Port,            /* Port Index (MAC_1 + n) */
SK_U16      StatAddr,         /* MIB counter base address */
SK_U32      SK_FAR *pVal)     /* ptr to return statistic value */
{

      if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
            
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
            
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
                  ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
            return(1);
      }
            
      GM_IN32(IoC, Port, StatAddr, pVal);

      return(0);
}     /* SkGmMacStatistic */


/******************************************************************************
 *
 *    SkGmResetCounter() - Clear MAC statistic counter
 *
 * Description:
 *    Force GMAC to clear its statistic counter.
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkGmResetCounter(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
unsigned int Port)      /* Port Index (MAC_1 + n) */
{
      SK_U16      Reg;  /* Phy Address Register */
      SK_U16      Word;
      int         i;

      GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);

      /* set MIB Clear Counter Mode */
      GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
      
      /* read all MIB Counters with Clear Mode set */
      for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
            /* the reset is performed only when the lower 16 bits are read */
            GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
      }
      
      /* clear MIB Clear Counter Mode */
      GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
      
      return(0);
}     /* SkGmResetCounter */


/******************************************************************************
 *
 *    SkGmOverflowStatus() - Gets the status of counter overflow interrupt
 *
 * Description:
 *    Checks the source causing an counter overflow interrupt. On success the
 *    resulting counter overflow status is written to <pStatus>, whereas the
 *    the following bit coding is used:
 *    63:56 - unused
 *    55:48 - TxRx interrupt register bit7:0
 *    32:47 - Rx interrupt register
 *    31:24 - unused
 *    23:16 - TxRx interrupt register bit15:8
 *    15:0  - Tx interrupt register
 *
 * Returns:
 *    0:  success
 *    1:  something went wrong
 */
int SkGmOverflowStatus(
SK_AC *pAC,                   /* adapter context */
SK_IOC      IoC,                    /* IO context */
unsigned int Port,                  /* Port Index (MAC_1 + n) */
SK_U16      IStatus,                /* Interupt Status from MAC */
SK_U64      SK_FAR *pStatus)  /* ptr for return overflow status value */
{
      SK_U64      Status;           /* Overflow status */
      SK_U16      RegVal;

      Status = 0;

      if ((IStatus & GM_IS_RX_CO_OV) != 0) {
            /* this register is self-clearing after read */
            GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
            Status |= (SK_U64)RegVal << 32;
      }
      
      if ((IStatus & GM_IS_TX_CO_OV) != 0) {
            /* this register is self-clearing after read */
            GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
            Status |= (SK_U64)RegVal;
      }
      
      /* this register is self-clearing after read */
      GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
      /* Rx overflow interrupt register bits (LoByte)*/
      Status |= (SK_U64)((SK_U8)RegVal) << 48;
      /* Tx overflow interrupt register bits (HiByte)*/
      Status |= (SK_U64)(RegVal >> 8) << 16;

      *pStatus = Status;

      return(0);
}     /* SkGmOverflowStatus */


#ifndef SK_SLIM
/******************************************************************************
 *
 *    SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
 *
 * Description:
 *  starts the cable diagnostic test if 'StartTest' is true
 *  gets the results if 'StartTest' is true
 *
 * NOTE:    this test is meaningful only when link is down
 *    
 * Returns:
 *    0:  success
 *    1:    no YUKON copper
 *    2:    test in progress
 */
int SkGmCableDiagStatus(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,              /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL     StartTest)  /* flag for start / get result */
{
      int         i;
      SK_U16      RegVal;
      SK_GEPORT   *pPrt;

      pPrt = &pAC->GIni.GP[Port];

      if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
            
            return(1);
      }

      if (StartTest) {
            /* only start the cable test */
            if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
                  /* apply TDR workaround from Marvell */
                  SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
                  
                  SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
                  SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
                  SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
                  SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
                  SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
            }

            /* set address to 0 for MDI[0] */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);

            /* Read Cable Diagnostic Reg */
            SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);

            /* start Cable Diagnostic Test */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
                  (SK_U16)(RegVal | PHY_M_CABD_ENA_TEST));
      
            return(0);
      }
      
      /* Read Cable Diagnostic Reg */
      SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);

      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
            ("PHY Cable Diag.=0x%04X\n", RegVal));

      if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
            /* test is running */
            return(2);
      }

      /* get the test results */
      for (i = 0; i < 4; i++)  {
            /* set address to i for MDI[i] */
            SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);

            /* get Cable Diagnostic values */
            SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);

            pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);

            pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
      }

      return(0);
}     /* SkGmCableDiagStatus */
#endif /* !SK_SLIM */
#endif /* YUKON */

/* End of file */

Generated by  Doxygen 1.6.0   Back to index