Logo Search packages:      
Sourcecode: u-boot-omap4 version File versions  Download package

skgeinit.c

/******************************************************************************
 *
 * Name:    skgeinit.c
 * Project: GEnesis, PCI Gigabit Ethernet Adapter
 * Version: $Revision: 1.85 $
 * Date:    $Date: 2003/02/05 15:30:33 $
 * Purpose: Contains functions to initialize the GE HW
 *
 ******************************************************************************/

/******************************************************************************
 *
 *    (C)Copyright 1998-2003 SysKonnect GmbH.
 *
 *    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.
 *
 ******************************************************************************/

/******************************************************************************
 *
 * History:
 *
 *    $Log: skgeinit.c,v $
 *    Revision 1.85  2003/02/05 15:30:33  rschmidt
 *    Corrected setting of GIHstClkFact (Host Clock Factor) and
 *    GIPollTimerVal (Descr. Poll Timer Init Value) for YUKON.
 *    Editorial changes.
 *
 *    Revision 1.84  2003/01/28 09:57:25  rschmidt
 *    Added detection of YUKON-Lite Rev. A0 (stored in GIYukonLite).
 *    Disabled Rx GMAC FIFO Flush for YUKON-Lite Rev. A0.
 *    Added support for CLK_RUN (YUKON-Lite).
 *    Added additional check of PME from D3cold for setting GIVauxAvail.
 *    Editorial changes.
 *
 *    Revision 1.83  2002/12/17 16:15:41  rschmidt
 *    Added default setting of PhyType (Copper) for YUKON.
 *    Added define around check for HW self test results.
 *    Editorial changes.
 *
 *    Revision 1.82  2002/12/05 13:40:21  rschmidt
 *    Added setting of Rx GMAC FIFO Flush Mask register.
 *    Corrected PhyType with new define SK_PHY_MARV_FIBER when
 *    YUKON Fiber board was found.
 *    Editorial changes.
 *
 *    Revision 1.81  2002/11/15 12:48:35  rschmidt
 *    Replaced message SKERR_HWI_E018 with SKERR_HWI_E024 for Rx queue error
 *    in SkGeStopPort().
 *    Added init for pAC->GIni.GIGenesis with SK_FALSE in YUKON-branch.
 *    Editorial changes.
 *
 *    Revision 1.80  2002/11/12 17:28:30  rschmidt
 *    Initialized GIPciSlot64 and GIPciClock66 in SkGeInit1().
 *    Reduced PCI FIFO watermarks for 32bit/33MHz bus in SkGeInitBmu().
 *    Editorial changes.
 *
 *    Revision 1.79  2002/10/21 09:31:02  mkarl
 *    Changed SkGeInitAssignRamToQueues(), removed call to
 *    SkGeInitAssignRamToQueues in SkGeInit1 and fixed compiler warning in
 *    SkGeInit1.
 *
 *    Revision 1.78  2002/10/16 15:55:07  mkarl
 *    Fixed a bug in SkGeInitAssignRamToQueues.
 *
 *    Revision 1.77  2002/10/14 15:07:22  rschmidt
 *    Corrected timeout handling for Rx queue in SkGeStopPort() (#10748)
 *    Editorial changes.
 *
 *    Revision 1.76  2002/10/11 09:24:38  mkarl
 *    Added check for HW self test results.
 *
 *    Revision 1.75  2002/10/09 16:56:44  mkarl
 *    Now call SkGeInitAssignRamToQueues() in Init Level 1 in order to assign
 *    the adapter memory to the queues. This default assignment is not suitable
 *    for dual net mode.
 *
 *    Revision 1.74  2002/09/12 08:45:06  rwahl
 *    Set defaults for PMSCap, PLinkSpeed & PLinkSpeedCap dependent on PHY.
 *
 *    Revision 1.73  2002/08/16 15:19:45  rschmidt
 *    Corrected check for Tx queues in SkGeCheckQSize().
 *    Added init for new entry GIGenesis and GICopperType
 *    Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
 *    Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
 *
 *    Revision 1.72  2002/08/12 13:38:55  rschmidt
 *    Added check if VAUX is available (stored in GIVauxAvail)
 *    Initialized PLinkSpeedCap in Port struct with SK_LSPEED_CAP_1000MBPS
 *    Editorial changes.
 *
 *    Revision 1.71  2002/08/08 16:32:58  rschmidt
 *    Added check for Tx queues in SkGeCheckQSize().
 *    Added start of Time Stamp Timer (YUKON) in SkGeInit2().
 *    Editorial changes.
 *
 *    Revision 1.70  2002/07/23 16:04:26  rschmidt
 *    Added init for GIWolOffs (HW-Bug in YUKON 1st rev.)
 *    Minor changes
 *
 *    Revision 1.69  2002/07/17 17:07:08  rwahl
 *    - SkGeInit1(): fixed PHY type debug output; corrected init of GIFunc
 *      table & GIMacType.
 *    - Editorial changes.
 *
 *    Revision 1.68  2002/07/15 18:38:31  rwahl
 *    Added initialization for MAC type dependent function table.
 *
 *    Revision 1.67  2002/07/15 15:45:39  rschmidt
 *    Added Tx Store & Forward for YUKON (GMAC Tx FIFO is only 1 kB)
 *    Replaced SK_PHY_MARV by SK_PHY_MARV_COPPER
 *    Editorial changes
 *
 *    Revision 1.66  2002/06/10 09:35:08  rschmidt
 *    Replaced C++ comments (//)
 *    Editorial changes
 *
 *    Revision 1.65  2002/06/05 08:33:37  rschmidt
 *    Changed GIRamSize and Reset sequence for YUKON.
 *    SkMacInit() replaced by SkXmInitMac() resp. SkGmInitMac()
 *
 *    Revision 1.64  2002/04/25 13:03:20  rschmidt
 *    Changes for handling YUKON.
 *    Removed reference to xmac_ii.h (not necessary).
 *    Moved all defines into header file.
 *    Replaced all SkXm...() functions with SkMac...() to handle also
 *    YUKON's GMAC.
 *    Added handling for GMAC FIFO in SkGeInitMacFifo(), SkGeStopPort().
 *    Removed 'goto'-directive from SkGeCfgSync(), SkGeCheckQSize().
 *    Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
 *    SkMacFlushTxFifo().
 *    Optimized timeout handling in SkGeStopPort().
 *    Initialized PLinkSpeed in Port struct with SK_LSPEED_AUTO.
 *    Release of GMAC Link Control reset in SkGeInit1().
 *    Initialized GIChipId and GIChipRev in GE Init structure.
 *    Added GIRamSize and PhyType values for YUKON.
 *    Removed use of PRxCmd to setup XMAC.
 *    Moved setting of XM_RX_DIS_CEXT to SkXmInitMac().
 *    Use of SkGeXmitLED() only for GENESIS.
 *    Changes for V-CPU support.
 *    Editorial changes.
 *
 *    Revision 1.63  2001/04/05 11:02:09  rassmann
 *    Stop Port check of the STOP bit did not take 2/18 sec as wanted.
 *
 *    Revision 1.62  2001/02/07 07:54:21  rassmann
 *    Corrected copyright.
 *
 *    Revision 1.61  2001/01/31 15:31:40  gklug
 *    fix: problem with autosensing an SR8800 switch
 *
 *    Revision 1.60  2000/10/18 12:22:21  cgoos
 *    Added workaround for half duplex hangup.
 *
 *    Revision 1.59  2000/10/10 11:22:06  gklug
 *    add: in manual half duplex mode ignore carrier extension errors
 *
 *    Revision 1.58  2000/10/02 14:10:27  rassmann
 *    Reading BCOM PHY after releasing reset until it returns a valid value.
 *
 *    Revision 1.57  2000/08/03 14:55:28  rassmann
 *    Waiting for I2C to be ready before de-initializing adapter
 *    (prevents sensors from hanging up).
 *
 *    Revision 1.56  2000/07/27 12:16:48  gklug
 *    fix: Stop Port check of the STOP bit does now take 2/18 sec as wanted
 *
 *    Revision 1.55  1999/11/22 13:32:26  cgoos
 *    Changed license header to GPL.
 *
 *    Revision 1.54  1999/10/26 07:32:54  malthoff
 *    Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics.
 *
 *    Revision 1.53  1999/08/12 19:13:50  malthoff
 *    Fix for 1000BT. Do not owerwrite XM_MMU_CMD when
 *    disabling receiver and transmitter. Other bits
 *    may be lost.
 *
 *    Revision 1.52  1999/07/01 09:29:54  gklug
 *    fix: DoInitRamQueue needs pAC
 *
 *    Revision 1.51  1999/07/01 08:42:21  gklug
 *    chg: use Store & forward for RAM buffer when Jumbos are used
 *
 *    Revision 1.50  1999/05/27 13:19:38  cgoos
 *    Added Tx PCI watermark initialization.
 *    Removed Tx RAM queue Store & Forward setting.
 *
 *    Revision 1.49  1999/05/20 14:32:45  malthoff
 *    SkGeLinkLED() is completly removed now.
 *
 *    Revision 1.48  1999/05/19 07:28:24  cgoos
 *    SkGeLinkLED no more available for drivers.
 *    Changes for 1000Base-T.
 *
 *    Revision 1.47  1999/04/08 13:57:45  gklug
 *    add: Init of new port struct fiels PLinkResCt
 *    chg: StopPort Timer check
 *
 *    Revision 1.46  1999/03/25 07:42:15  malthoff
 *    SkGeStopPort(): Add workaround for cache incoherency.
 *                Create error log entry, disable port, and
 *                exit loop if it does not terminate.
 *    Add XM_RX_LENERR_OK to the default value for the
 *    XMAC receive command register.
 *
 *    Revision 1.45  1999/03/12 16:24:47  malthoff
 *    Remove PPollRxD and PPollTxD.
 *    Add check for GIPollTimerVal.
 *
 *    Revision 1.44  1999/03/12 13:40:23  malthoff
 *    Fix: SkGeXmitLED(), SK_LED_TST mode does not work.
 *    Add: Jumbo frame support.
 *    Chg: Resolution of parameter IntTime in SkGeCfgSync().
 *
 *    Revision 1.43  1999/02/09 10:29:46  malthoff
 *    Bugfix: The previous modification again also for the second location.
 *
 *    Revision 1.42  1999/02/09 09:35:16  malthoff
 *    Bugfix: The bits '66 MHz Capable' and 'NEWCAP are reset while
 *          clearing the error bits in the PCI status register.
 *
 *    Revision 1.41  1999/01/18 13:07:02  malthoff
 *    Bugfix: Do not use CFG cycles after during Init- or Runtime, because
 *          they may not be available after Boottime.
 *
 *    Revision 1.40  1999/01/11 12:40:49  malthoff
 *    Bug fix: PCI_STATUS: clearing error bits sets the UDF bit.
 *
 *    Revision 1.39  1998/12/11 15:17:33  gklug
 *    chg: Init LipaAutoNeg with Unknown
 *
 *    Revision 1.38  1998/12/10 11:02:57  malthoff
 *    Disable Error Log Message when calling SkGeInit(level 2)
 *    more than once.
 *
 *    Revision 1.37  1998/12/07 12:18:25  gklug
 *    add: refinement of autosense mode: take into account the autoneg cap of LiPa
 *
 *    Revision 1.36  1998/12/07 07:10:39  gklug
 *    fix: init values of LinkBroken/ Capabilities for management
 *
 *    Revision 1.35  1998/12/02 10:56:20  gklug
 *    fix: do NOT init LoinkSync Counter.
 *
 *    Revision 1.34  1998/12/01 10:53:21  gklug
 *    add: init of additional Counters for workaround
 *
 *    Revision 1.33  1998/12/01 10:00:49  gklug
 *    add: init PIsave var in Port struct
 *
 *    Revision 1.32  1998/11/26 14:50:40  gklug
 *    chg: Default is autosensing with AUTOFULL mode
 *
 *    Revision 1.31  1998/11/25 15:36:16  gklug
 *    fix: do NOT stop LED Timer when port should be stopped
 *
 *    Revision 1.30  1998/11/24 13:15:28  gklug
 *    add: Init PCkeckPar struct member
 *
 *    Revision 1.29  1998/11/18 13:19:27  malthoff
 *    Disable packet arbiter timeouts on receive side.
 *    Use maximum timeout value for packet arbiter
 *    transmit timeouts.
 *    Add TestStopBit() function to handle stop RX/TX
 *    problem with active descriptor poll timers.
 *    Bug Fix: Descriptor Poll Timer not started, because
 *    GIPollTimerVal was initialized with 0.
 *
 *    Revision 1.28  1998/11/13 14:24:26  malthoff
 *    Bug Fix: SkGeStopPort() may hang if a Packet Arbiter Timout
 *    is pending or occurs while waiting for TX_STOP and RX_STOP.
 *    The PA timeout is cleared now while waiting for TX- or RX_STOP.
 *
 *    Revision 1.27  1998/11/02 11:04:36  malthoff
 *    fix the last fix
 *
 *    Revision 1.26  1998/11/02 10:37:03  malthoff
 *    Fix: SkGePollTxD() enables always the synchronounous poll timer.
 *
 *    Revision 1.25  1998/10/28 07:12:43  cgoos
 *    Fixed "LED_STOP" in SkGeLnkSyncCnt, "== SK_INIT_IO" in SkGeInit.
 *    Removed: Reset of RAM Interface in SkGeStopPort.
 *
 *    Revision 1.24  1998/10/27 08:13:12  malthoff
 *    Remove temporary code.
 *
 *    Revision 1.23  1998/10/26 07:45:03  malthoff
 *    Add Address Calculation Workaround: If the EPROM byte
 *    Id is 3, the address offset is 512 kB.
 *    Initialize default values for PLinkMode and PFlowCtrlMode.
 *
 *    Revision 1.22  1998/10/22 09:46:47  gklug
 *    fix SysKonnectFileId typo
 *
 *    Revision 1.21  1998/10/20 12:11:56  malthoff
 *    Don't dendy the Queue config if the size of the unused
 *    Rx qeueu is zero.
 *
 *    Revision 1.20  1998/10/19 07:27:58  malthoff
 *    SkGeInitRamIface() is public to be called by diagnostics.
 *
 *    Revision 1.19  1998/10/16 13:33:45  malthoff
 *    Fix: enabling descriptor polling is not allowed until
 *    the descriptor addresses are set. Descriptor polling
 *    must be handled by the driver.
 *
 *    Revision 1.18  1998/10/16 10:58:27  malthoff
 *    Remove temp. code for Diag prototype.
 *    Remove lint warning for dummy reads.
 *    Call SkGeLoadLnkSyncCnt() during SkGeInitPort().
 *
 *    Revision 1.17  1998/10/14 09:16:06  malthoff
 *    Change parameter LimCount and programming of
 *    the limit counter in SkGeCfgSync().
 *
 *    Revision 1.16  1998/10/13 09:21:16  malthoff
 *    Don't set XM_RX_SELF_RX in RxCmd Reg, because it's
 *    like a Loopback Mode in half duplex.
 *
 *    Revision 1.15  1998/10/09 06:47:40  malthoff
 *    SkGeInitMacArb(): set recovery counters init value
 *    to zero although this counters are not uesd.
 *    Bug fix in Rx Upper/Lower Pause Threshold calculation.
 *    Add XM_RX_SELF_RX to RxCmd.
 *
 *    Revision 1.14  1998/10/06 15:15:53  malthoff
 *    Make sure no pending IRQ is cleared in SkGeLoadLnkSyncCnt().
 *
 *    Revision 1.13  1998/10/06 14:09:36  malthoff
 *    Add SkGeLoadLnkSyncCnt(). Modify
 *    the 'port stopped' condition according
 *    to the current problem report.
 *
 *    Revision 1.12  1998/10/05 08:17:21  malthoff
 *    Add functions: SkGePollRxD(), SkGePollTxD(),
 *    DoCalcAddr(), SkGeCheckQSize(),
 *    DoInitRamQueue(), and SkGeCfgSync().
 *    Add coding for SkGeInitMacArb(), SkGeInitPktArb(),
 *    SkGeInitMacFifo(), SkGeInitRamBufs(),
 *    SkGeInitRamIface(), and SkGeInitBmu().
 *
 *    Revision 1.11  1998/09/29 08:26:29  malthoff
 *    bug fix: SkGeInit0() 'i' should be increment.
 *
 *    Revision 1.10  1998/09/28 13:19:01  malthoff
 *    Coding time: Save the done work.
 *    Modify SkGeLinkLED(), add SkGeXmitLED(),
 *    define SkGeCheckQSize(), SkGeInitMacArb(),
 *    SkGeInitPktArb(), SkGeInitMacFifo(),
 *    SkGeInitRamBufs(), SkGeInitRamIface(),
 *    and SkGeInitBmu(). Do coding for SkGeStopPort(),
 *    SkGeInit1(), SkGeInit2(), and SkGeInit3().
 *    Do coding for SkGeDinit() and SkGeInitPort().
 *
 *    Revision 1.9  1998/09/16 14:29:05  malthoff
 *    Some minor changes.
 *
 *    Revision 1.8  1998/09/11 05:29:14  gklug
 *    add: init state of a port
 *
 *    Revision 1.7  1998/09/04 09:26:25  malthoff
 *    Short temporary modification.
 *
 *    Revision 1.6  1998/09/04 08:27:59  malthoff
 *    Remark the do-while in StopPort() because it never ends
 *    without a GE adapter.
 *
 *    Revision 1.5  1998/09/03 14:05:45  malthoff
 *    Change comment for SkGeInitPort(). Do not
 *    repair the queue sizes if invalid.
 *
 *    Revision 1.4  1998/09/03 10:03:19  malthoff
 *    Implement the new interface according to the
 *    reviewed interface specification.
 *
 *    Revision 1.3  1998/08/19 09:11:25  gklug
 *    fix: struct are removed from c-source (see CCC)
 *
 *    Revision 1.2  1998/07/28 12:33:58  malthoff
 *    Add 'IoC' parameter in function declaration and SK IO macros.
 *
 *    Revision 1.1  1998/07/23 09:48:57  malthoff
 *    Creation. First dummy 'C' file.
 *    SkGeInit(Level 0) is card_start for GE.
 *    SkGeDeInit() is card_stop for GE.
 *
 *
 ******************************************************************************/

#include <config.h>

#ifdef CONFIG_SK98

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

/* global variables ***********************************************************/

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

static const char SysKonnectFileId[] =
      "@(#)$Id: skgeinit.c,v 1.85 2003/02/05 15:30:33 rschmidt Exp $ (C) SK ";

struct s_QOffTab {
      int   RxQOff;           /* Receive Queue Address Offset */
      int   XsQOff;           /* Sync Tx Queue Address Offset */
      int   XaQOff;           /* Async Tx Queue Address Offset */
};
static struct s_QOffTab QOffTab[] = {
      {Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
};


/******************************************************************************
 *
 *    SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring
 *
 * Description:
 *    Enable or disable the descriptor polling of the receive descriptor
 *    ring (RxD) for port 'Port'.
 *    The new configuration is *not* saved over any SkGeStopPort() and
 *    SkGeInitPort() calls.
 *
 * Returns:
 *    nothing
 */
void SkGePollRxD(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL PollRxD)  /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
{
      SK_GEPORT *pPrt;

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

      SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (PollRxD) ?
            CSR_ENA_POL : CSR_DIS_POL);
}     /* SkGePollRxD */


/******************************************************************************
 *
 *    SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
 *
 * Description:
 *    Enable or disable the descriptor polling of the transmit descriptor
 *    ring(s) (TxD) for port 'Port'.
 *    The new configuration is *not* saved over any SkGeStopPort() and
 *    SkGeInitPort() calls.
 *
 * Returns:
 *    nothing
 */
void SkGePollTxD(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_BOOL PollTxD)  /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
{
      SK_GEPORT *pPrt;
      SK_U32      DWord;

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

      DWord = (PollTxD) ? CSR_ENA_POL : CSR_DIS_POL;

      if (pPrt->PXSQSize != 0) {
            SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
      }

      if (pPrt->PXAQSize != 0) {
            SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
      }
}     /* SkGePollTxD */


/******************************************************************************
 *
 *    SkGeYellowLED() - Switch the yellow LED on or off.
 *
 * Description:
 *    Switch the yellow LED on or off.
 *
 * Note:
 *    This function may be called any time after SkGeInit(Level 1).
 *
 * Returns:
 *    nothing
 */
void SkGeYellowLED(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         State)            /* yellow LED state, 0 = OFF, 0 != ON */
{
      if (State == 0) {
            /* Switch yellow LED OFF */
            SK_OUT8(IoC, B0_LED, LED_STAT_OFF);
      }
      else {
            /* Switch yellow LED ON */
            SK_OUT8(IoC, B0_LED, LED_STAT_ON);
      }
}     /* SkGeYellowLED */


/******************************************************************************
 *
 *    SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
 *
 * Description:
 *    The Rx or Tx LED which is specified by 'Led' will be
 *    enabled, disabled or switched on in test mode.
 *
 * Note:
 *    'Led' must contain the address offset of the LEDs INI register.
 *
 * Usage:
 *    SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
 *
 * Returns:
 *    nothing
 */
void SkGeXmitLED(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Led,        /* offset to the LED Init Value register */
int         Mode)       /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
{
      SK_U32      LedIni;

      switch (Mode) {
      case SK_LED_ENA:
            LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
            SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
            SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
            break;
      case SK_LED_TST:
            SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
            SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
            SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
            break;
      case SK_LED_DIS:
      default:
            /*
             * Do NOT stop the LED Timer here. The LED might be
             * in on state. But it needs to go off.
             */
            SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
            SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
            break;
      }

      /*
       * 1000BT: The Transmit LED is driven by the PHY.
       * But the default LED configuration is used for
       * Level One and Broadcom PHYs.
       * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
       * (In this case it has to be added here. But we will see. XXX)
       */
}     /* SkGeXmitLED */


/******************************************************************************
 *
 *    DoCalcAddr() - Calculates the start and the end address of a queue.
 *
 * Description:
 *    This function calculates the start and the end address of a queue.
 *  Afterwards the 'StartVal' is incremented to the next start position.
 *    If the port is already initialized the calculated values
 *    will be checked against the configured values and an
 *    error will be returned, if they are not equal.
 *    If the port is not initialized the values will be written to
 *    *StartAdr and *EndAddr.
 *
 * Returns:
 *    0:    success
 *    1:    configuration error
 */
static int DoCalcAddr(
SK_AC       *pAC,                   /* adapter context */
SK_GEPORT   *pPrt,                  /* port index */
int               QuSize,                 /* size of the queue to configure in kB */
SK_U32            *StartVal,        /* start value for address calculation */
SK_U32            *QuStartAddr,     /* start addr to calculate */
SK_U32            *QuEndAddr)       /* end address to calculate */
{
      SK_U32      EndVal;
      SK_U32      NextStart;
      int         Rtv;

      Rtv = 0;
      if (QuSize == 0) {
            EndVal = *StartVal;
            NextStart = EndVal;
      }
      else {
            EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
            NextStart = EndVal + 1;
      }

      if (pPrt->PState >= SK_PRT_INIT) {
            if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
                  Rtv = 1;
            }
      }
      else {
            *QuStartAddr = *StartVal;
            *QuEndAddr = EndVal;
      }

      *StartVal = NextStart;
      return(Rtv);
}     /* DoCalcAddr */

/******************************************************************************
 *
 *    SkGeInitAssignRamToQueues() - allocate default queue sizes
 *
 * Description:
 *    This function assigns the memory to the different queues and ports.
 *    When DualNet is set to SK_TRUE all ports get the same amount of memory.
 *  Otherwise the first port gets most of the memory and all the
 *    other ports just the required minimum.
 *    This function can only be called when pAC->GIni.GIRamSize and
 *    pAC->GIni.GIMacsFound have been initialized, usually this happens
 *    at init level 1
 *
 * Returns:
 *    0 - ok
 *    1 - invalid input values
 *    2 - not enough memory
 */

int SkGeInitAssignRamToQueues(
SK_AC *pAC,             /* Adapter context */
int         ActivePort,       /* Active Port in RLMT mode */
SK_BOOL     DualNet)          /* adapter context */
{
      int   i;
      int   UsedKilobytes;                /* memory already assigned */
      int   ActivePortKilobytes;    /* memory available for active port */
      SK_GEPORT *pGePort;

      UsedKilobytes = 0;

      if (ActivePort >= pAC->GIni.GIMacsFound) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
                  ("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
                  ActivePort));
            return(1);
      }
      if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
            ((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
                  ("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
                   pAC->GIni.GIRamSize));
            return(2);
      }


      if (DualNet) {
            /* every port gets the same amount of memory */
            ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
            for (i = 0; i < pAC->GIni.GIMacsFound; i++) {

                  pGePort = &pAC->GIni.GP[i];

                  /* take away the minimum memory for active queues */
                  ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);

                  /* receive queue gets the minimum + 80% of the rest */
                  pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
                        ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
                        + SK_MIN_RXQ_SIZE;

                  ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);

                  /* synchronous transmit queue */
                  pGePort->PXSQSize = 0;

                  /* asynchronous transmit queue */
                  pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
                        SK_MIN_TXQ_SIZE);
            }
      }
      else {
            /* Rlmt Mode or single link adapter */

            /* Set standby queue size defaults for all standby ports */
            for (i = 0; i < pAC->GIni.GIMacsFound; i++) {

                  if (i != ActivePort) {
                        pGePort = &pAC->GIni.GP[i];

                        pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
                        pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
                        pGePort->PXSQSize = 0;

                        /* Count used RAM */
                        UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
                  }
            }
            /* what's left? */
            ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;

            /* assign it to the active port */
            /* first take away the minimum memory */
            ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
            pGePort = &pAC->GIni.GP[ActivePort];

            /* receive queue get's the minimum + 80% of the rest */
            pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
                  (unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;

            ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);

            /* synchronous transmit queue */
            pGePort->PXSQSize = 0;

            /* asynchronous transmit queue */
            pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
                  SK_MIN_TXQ_SIZE;
      }
#ifdef VCPU
      VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
            pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
#endif /* VCPU */

      return(0);
}     /* SkGeInitAssignRamToQueues */

/******************************************************************************
 *
 *    SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
 *
 * Description:
 *    This function verifies the Queue Size Configuration specified
 *    in the variables PRxQSize, PXSQSize, and PXAQSize of all
 *    used ports.
 *    This requirements must be fullfilled to have a valid configuration:
 *          - The size of all queues must not exceed GIRamSize.
 *          - The queue sizes must be specified in units of 8 kB.
 *          - The size of Rx queues of available ports must not be
 *            smaller than 16 kB.
 *          - The size of at least one Tx queue (synch. or asynch.)
 *        of available ports must not be smaller than 16 kB
 *        when Jumbo Frames are used.
 *          - The RAM start and end addresses must not be changed
 *            for ports which are already initialized.
 *    Furthermore SkGeCheckQSize() defines the Start and End Addresses
 *  of all ports and stores them into the HWAC port   structure.
 *
 * Returns:
 *    0:    Queue Size Configuration valid
 *    1:    Queue Size Configuration invalid
 */
static int SkGeCheckQSize(
SK_AC  *pAC,            /* adapter context */
int          Port)            /* port index */
{
      SK_GEPORT *pPrt;
      int   UsedMem;    /* total memory used (max. found ports) */
      int   i;
      int   Rtv;
      int   Rtv2;
      SK_U32      StartAddr;

      UsedMem = 0;
      Rtv = 0;
      for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
            pPrt = &pAC->GIni.GP[i];

            if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
                  (pPrt->PXSQSize & QZ_UNITS) != 0 ||
                  (pPrt->PXAQSize & QZ_UNITS) != 0) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
                  return(1);
            }

            if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
                  return(1);
            }

            /*
             * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
             * if Jumbo Frames are used, this size has to be >= 16 kB.
             */
            if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
                  (pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
          ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
                   (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
                        return(1);
            }

            UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
      }

      if (UsedMem > pAC->GIni.GIRamSize) {
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
            return(1);
      }

      /* Now start address calculation */
      StartAddr = pAC->GIni.GIRamOffs;
      for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
            pPrt = &pAC->GIni.GP[i];

            /* Calculate/Check values for the receive queue */
            Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
                  &pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
            Rtv |= Rtv2;

            /* Calculate/Check values for the synchronous Tx queue */
            Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
                  &pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
            Rtv |= Rtv2;

            /* Calculate/Check values for the asynchronous Tx queue */
            Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
                  &pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
            Rtv |= Rtv2;

            if (Rtv) {
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
                  return(1);
            }
      }

      return(0);
}     /* SkGeCheckQSize */


/******************************************************************************
 *
 *    SkGeInitMacArb() - Initialize the MAC Arbiter
 *
 * Description:
 *    This function initializes the MAC Arbiter.
 *    It must not be called if there is still an
 *    initialized or active port.
 *
 * Returns:
 *    nothing
 */
static void SkGeInitMacArb(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      /* release local reset */
      SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);

      /* configure timeout values */
      SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
      SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
      SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
      SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);

      SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
      SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
      SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
      SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);

      /* recovery values are needed for XMAC II Rev. B2 only */
      /* Fast Output Enable Mode was intended to use with Rev. B2, but now? */

      /*
       * There is no start or enable button to push, therefore
       * the MAC arbiter is configured and enabled now.
       */
}     /* SkGeInitMacArb */


/******************************************************************************
 *
 *    SkGeInitPktArb() - Initialize the Packet Arbiter
 *
 * Description:
 *    This function initializes the Packet Arbiter.
 *    It must not be called if there is still an
 *    initialized or active port.
 *
 * Returns:
 *    nothing
 */
static void SkGeInitPktArb(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      /* release local reset */
      SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);

      /* configure timeout values */
      SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
      SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
      SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
      SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);

      /*
       * enable timeout timers if jumbo frames not used
       * NOTE: the packet arbiter timeout interrupt is needed for
       * half duplex hangup workaround
       */
      if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
            if (pAC->GIni.GIMacsFound == 1) {
                  SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
            }
            else {
                  SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
            }
      }
}     /* SkGeInitPktArb */


/******************************************************************************
 *
 *    SkGeInitMacFifo() - Initialize the MAC FIFOs
 *
 * Description:
 *    Initialize all MAC FIFOs of the specified port
 *
 * Returns:
 *    nothing
 */
static void SkGeInitMacFifo(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_U16      Word;
#ifdef VCPU
      SK_U32      DWord;
#endif /* VCPU */
      /*
       * For each FIFO:
       *    - release local reset
       *    - use default value for MAC FIFO size
       *    - setup defaults for the control register
       *    - enable the FIFO
       */

      Word = GMF_RX_CTRL_DEF;

      if (pAC->GIni.GIGenesis) {
            /* Configure Rx MAC FIFO */
            SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
            SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
            SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);

            /* Configure Tx MAC FIFO */
            SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
            SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
            SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);

            /* Enable frame flushing if jumbo frames used */
            if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
                  SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
            }
      }
      else {
            /* set Rx GMAC FIFO Flush Mask */
            SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);

            if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) {

                  Word &= ~GMF_RX_F_FL_ON;
            }

            /* Configure Rx MAC FIFO */
            SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
            SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);

            /* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */
            SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);

            /* Configure Tx MAC FIFO */
            SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
            SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);

#ifdef VCPU
            SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
            SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
#endif /* VCPU */

            /* set Tx GMAC FIFO Almost Empty Threshold */
/*          SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
      }
}     /* SkGeInitMacFifo */


/******************************************************************************
 *
 *    SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
 *
 * Description:
 *    This function starts the Link Sync Counter of the specified
 *    port and enables the generation of an Link Sync IRQ.
 *    The Link Sync Counter may be used to detect an active link,
 *    if autonegotiation is not used.
 *
 * Note:
 *    o To ensure receiving the Link Sync Event the LinkSyncCounter
 *      should be initialized BEFORE clearing the XMAC's reset!
 *    o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
 *      function.
 *
 * Returns:
 *    nothing
 */
void SkGeLoadLnkSyncCnt(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_U32      CntVal)           /* Counter value */
{
      SK_U32      OrgIMsk;
      SK_U32      NewIMsk;
      SK_U32      ISrc;
      SK_BOOL     IrqPend;

      /* stop counter */
      SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP);

      /*
       * ASIC problem:
       * Each time starting the Link Sync Counter an IRQ is generated
       * by the adapter. See problem report entry from 21.07.98
       *
       * Workaround:    Disable Link Sync IRQ and clear the unexpeced IRQ
       *          if no IRQ is already pending.
       */
      IrqPend = SK_FALSE;
      SK_IN32(IoC, B0_ISRC, &ISrc);
      SK_IN32(IoC, B0_IMSK, &OrgIMsk);
      if (Port == MAC_1) {
            NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
            if ((ISrc & IS_LNK_SYNC_M1) != 0) {
                  IrqPend = SK_TRUE;
            }
      }
      else {
            NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
            if ((ISrc & IS_LNK_SYNC_M2) != 0) {
                  IrqPend = SK_TRUE;
            }
      }
      if (!IrqPend) {
            SK_OUT32(IoC, B0_IMSK, NewIMsk);
      }

      /* load counter */
      SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);

      /* start counter */
      SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START);

      if (!IrqPend) {
            /* clear the unexpected IRQ, and restore the interrupt mask */
            SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ);
            SK_OUT32(IoC, B0_IMSK, OrgIMsk);
      }
}     /* SkGeLoadLnkSyncCnt*/


/******************************************************************************
 *
 *    SkGeCfgSync() - Configure synchronous bandwidth for this port.
 *
 * Description:
 *    This function may be used to configure synchronous bandwidth
 *    to the specified port. This may be done any time after
 *    initializing the port. The configuration values are NOT saved
 *    in the HWAC port structure and will be overwritten any
 *    time when stopping and starting the port.
 *    Any values for the synchronous configuration will be ignored
 *    if the size of the synchronous queue is zero!
 *
 *    The default configuration for the synchronous service is
 *    TXA_ENA_FSYNC. This means if the size of
 *    the synchronous queue is unequal zero but no specific
 *    synchronous bandwidth is configured, the synchronous queue
 *    will always have the 'unlimited' transmit priority!
 *
 *    This mode will be restored if the synchronous bandwidth is
 *    deallocated ('IntTime' = 0 and 'LimCount' = 0).
 *
 * Returns:
 *    0:    success
 *    1:    parameter configuration error
 *    2:    try to configure quality of service although no
 *          synchronous queue is configured
 */
int SkGeCfgSync(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port,       /* Port Index (MAC_1 + n) */
SK_U32      IntTime,    /* Interval Timer Value in units of 8ns */
SK_U32      LimCount,   /* Number of bytes to transfer during IntTime */
int         SyncMode)   /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
{
      int Rtv;

      Rtv = 0;

      /* check the parameters */
      if (LimCount > IntTime ||
            (LimCount == 0 && IntTime != 0) ||
            (LimCount != 0 && IntTime == 0)) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
            return(1);
      }

      if (pAC->GIni.GP[Port].PXSQSize == 0) {
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
            return(2);
      }

      /* calculate register values */
      IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
      LimCount = LimCount / 8;

      if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
            return(1);
      }

      /*
       * - Enable 'Force Sync' to ensure the synchronous queue
       *   has the priority while configuring the new values.
       * - Also 'disable alloc' to ensure the settings complies
       *   to the SyncMode parameter.
       * - Disable 'Rate Control' to configure the new values.
       * - write IntTime and LimCount
       * - start 'Rate Control' and disable 'Force Sync'
       *   if Interval Timer or Limit Counter not zero.
       */
      SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
            TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);

      SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
      SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);

      SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
            (SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));

      if (IntTime != 0 || LimCount != 0) {
            SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
      }

      return(0);
}     /* SkGeCfgSync */


/******************************************************************************
 *
 *    DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
 *
 * Desccription:
 *    If the queue is used, enable and initialize it.
 *    Make sure the queue is still reset, if it is not used.
 *
 * Returns:
 *    nothing
 */
static void DoInitRamQueue(
SK_AC *pAC,             /* adapter context */
SK_IOC      IoC,              /* IO context */
int         QuIoOffs,         /* Queue IO Address Offset */
SK_U32      QuStartAddr,      /* Queue Start Address */
SK_U32      QuEndAddr,        /* Queue End Address */
int         QuType)                 /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
{
      SK_U32      RxUpThresVal;
      SK_U32      RxLoThresVal;

      if (QuStartAddr != QuEndAddr) {
            /* calculate thresholds, assume we have a big Rx queue */
            RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
            RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;

            /* build HW address format */
            QuStartAddr = QuStartAddr / 8;
            QuEndAddr = QuEndAddr / 8;

            /* release local reset */
            SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);

            /* configure addresses */
            SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
            SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
            SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
            SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);

            switch (QuType) {
            case SK_RX_SRAM_Q:
                  /* configure threshold for small Rx Queue */
                  RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;

                  /* continue with SK_RX_BRAM_Q */
            case SK_RX_BRAM_Q:
                  /* write threshold for Rx Queue */

                  SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
                  SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);

                  /* the high priority threshold not used */
                  break;
            case SK_TX_RAM_Q:
                  /*
                   * Do NOT use Store & Forward under normal operation due to
                   * performance optimization (GENESIS only).
                   * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
                   * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
                   * we NEED Store & Forward of the RAM buffer.
                   */
                  if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
                        !pAC->GIni.GIGenesis) {
                        /* enable Store & Forward Mode for the Tx Side */
                        SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
                  }
                  break;
            }

            /* set queue operational */
            SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
      }
      else {
            /* ensure the queue is still disabled */
            SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
      }
}     /* DoInitRamQueue */


/******************************************************************************
 *
 *    SkGeInitRamBufs() - Initialize the RAM Buffer Queues
 *
 * Description:
 *    Initialize all RAM Buffer Queues of the specified port
 *
 * Returns:
 *    nothing
 */
static void SkGeInitRamBufs(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT *pPrt;
      int RxQType;

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

      if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
            RxQType = SK_RX_SRAM_Q;       /* small Rx Queue */
      }
      else {
            RxQType = SK_RX_BRAM_Q;       /* big Rx Queue */
      }

      DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
            pPrt->PRxQRamEnd, RxQType);

      DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
            pPrt->PXsQRamEnd, SK_TX_RAM_Q);

      DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
            pPrt->PXaQRamEnd, SK_TX_RAM_Q);

}     /* SkGeInitRamBufs */


/******************************************************************************
 *
 *    SkGeInitRamIface() - Initialize the RAM Interface
 *
 * Description:
 *    This function initializes the Adapters RAM Interface.
 *
 * Note:
 *    This function is used in the diagnostics.
 *
 * Returns:
 *    nothing
 */
void SkGeInitRamIface(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      /* release local reset */
      SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);

      /* configure timeout values */
      SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
      SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);

}     /* SkGeInitRamIface */


/******************************************************************************
 *
 *    SkGeInitBmu() - Initialize the BMU state machines
 *
 * Description:
 *    Initialize all BMU state machines of the specified port
 *
 * Returns:
 *    nothing
 */
static void SkGeInitBmu(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port Index (MAC_1 + n) */
{
      SK_GEPORT   *pPrt;
      SK_U32            RxWm;
      SK_U32            TxWm;

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

      RxWm = SK_BMU_RX_WM;
      TxWm = SK_BMU_TX_WM;

      if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
            /* for better performance */
            RxWm /= 2;
            TxWm /= 2;
      }

      /* Rx Queue: Release all local resets and set the watermark */
      SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
      SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);

      /*
       * Tx Queue: Release all local resets if the queue is used !
       *          set watermark
       */
      if (pPrt->PXSQSize != 0) {
            SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
            SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
      }

      if (pPrt->PXAQSize != 0) {
            SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
            SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
      }
      /*
       * Do NOT enable the descriptor poll timers here, because
       * the descriptor addresses are not specified yet.
       */
}     /* SkGeInitBmu */


/******************************************************************************
 *
 *    TestStopBit() -   Test the stop bit of the queue
 *
 * Description:
 *    Stopping a queue is not as simple as it seems to be.
 *    If descriptor polling is enabled, it may happen
 *    that RX/TX stop is done and SV idle is NOT set.
 *    In this case we have to issue another stop command.
 *
 * Returns:
 *    The queues control status register
 */
static SK_U32 TestStopBit(
SK_AC *pAC,       /* Adapter Context */
SK_IOC      IoC,        /* IO Context */
int         QuIoOffs)   /* Queue IO Address Offset */
{
      SK_U32      QuCsr;      /* CSR contents */

      SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);

      if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
            /* Stop Descriptor overridden by start command */
            SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);

            SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
      }

      return(QuCsr);
}     /* TestStopBit */


/******************************************************************************
 *
 *    SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
 *
 * Description:
 *    After calling this function the descriptor rings and Rx and Tx
 *    queues of this port may be reconfigured.
 *
 *    It is possible to stop the receive and transmit path separate or
 *    both together.
 *
 *    Dir = SK_STOP_TX  Stops the transmit path only and resets the MAC.
 *                      The receive queue is still active and
 *                      the pending Rx frames may be still transferred
 *                      into the RxD.
 *          SK_STOP_RX  Stop the receive path. The tansmit path
 *                      has to be stopped once before.
 *          SK_STOP_ALL SK_STOP_TX + SK_STOP_RX
 *
 *    RstMode = SK_SOFT_RST   Resets the MAC. The PHY is still alive.
 *                SK_HARD_RST Resets the MAC and the PHY.
 *
 * Example:
 *    1) A Link Down event was signaled for a port. Therefore the activity
 *    of this port should be stopped and a hardware reset should be issued
 *    to enable the workaround of XMAC errata #2. But the received frames
 *    should not be discarded.
 *          ...
 *          SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
 *          (transfer all pending Rx frames)
 *          SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
 *          ...
 *
 *    2) An event was issued which request the driver to switch
 *    the 'virtual active' link to an other already active port
 *    as soon as possible. The frames in the receive queue of this
 *    port may be lost. But the PHY must not be reset during this
 *    event.
 *          ...
 *          SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
 *          ...
 *
 * Extended Description:
 *    If SK_STOP_TX is set,
 *          o disable the MAC's receive and transmitter to prevent
 *            from sending incomplete frames
 *          o stop the port's transmit queues before terminating the
 *            BMUs to prevent from performing incomplete PCI cycles
 *            on the PCI bus
 *          - The network Rx and Tx activity and PCI Tx transfer is
 *            disabled now.
 *          o reset the MAC depending on the RstMode
 *          o Stop Interval Timer and Limit Counter of Tx Arbiter,
 *            also disable Force Sync bit and Enable Alloc bit.
 *          o perform a local reset of the port's Tx path
 *                - reset the PCI FIFO of the async Tx queue
 *                - reset the PCI FIFO of the sync Tx queue
 *                - reset the RAM Buffer async Tx queue
 *                - reset the RAM Buffer sync Tx queue
 *                - reset the MAC Tx FIFO
 *          o switch Link and Tx LED off, stop the LED counters
 *
 *    If SK_STOP_RX is set,
 *          o stop the port's receive queue
 *          - The path data transfer activity is fully stopped now.
 *          o perform a local reset of the port's Rx path
 *                - reset the PCI FIFO of the Rx queue
 *                - reset the RAM Buffer receive queue
 *                - reset the MAC Rx FIFO
 *          o switch Rx LED off, stop the LED counter
 *
 *    If all ports are stopped,
 *          o reset the RAM Interface.
 *
 * Notes:
 *    o This function may be called during the driver states RESET_PORT and
 *      SWITCH_PORT.
 */
void SkGeStopPort(
SK_AC *pAC, /* adapter context */
SK_IOC      IoC,  /* I/O context */
int         Port, /* port to stop (MAC_1 + n) */
int         Dir,  /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
int         RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
{
#ifndef SK_DIAG
      SK_EVPARA Para;
#endif /* !SK_DIAG */
      SK_GEPORT *pPrt;
      SK_U32      DWord;
      SK_U32      XsCsr;
      SK_U32      XaCsr;
      SK_U64      ToutStart;
      int         i;
      int         ToutCnt;

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

      if ((Dir & SK_STOP_TX) != 0) {
            /* disable receiver and transmitter */
            SkMacRxTxDisable(pAC, IoC, Port);

            /* stop both transmit queues */
            /*
             * If the BMU is in the reset state CSR_STOP will terminate
             * immediately.
             */
            SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP);
            SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP);

            ToutStart = SkOsGetTime(pAC);
            ToutCnt = 0;
            do {
                  /*
                   * Clear packet arbiter timeout to make sure
                   * this loop will terminate.
                   */
                  SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_TX1 :
                        PA_CLR_TO_TX2);

                  /*
                   * If the transfer stucks at the MAC the STOP command will not
                   * terminate if we don't flush the XMAC's transmit FIFO !
                   */
                  SkMacFlushTxFifo(pAC, IoC, Port);

                  XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
                  XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);

                  if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
                        /*
                         * Timeout of 1/18 second reached.
                         * This needs to be checked at 1/18 sec only.
                         */
                        ToutCnt++;
                        if (ToutCnt > 1) {
                              /* Might be a problem when the driver event handler
                               * calls StopPort again. XXX.
                               */

                              /* Fatal Error, Loop aborted */
                              SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
                                    SKERR_HWI_E018MSG);
#ifndef SK_DIAG
                              Para.Para64 = Port;
                              SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
#endif /* !SK_DIAG */
                              return;
                        }
                        /*
                         * Cache incoherency workaround: Assume a start command
                         * has been lost while sending the frame.
                         */
                        ToutStart = SkOsGetTime(pAC);

                        if ((XsCsr & CSR_STOP) != 0) {
                              SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
                        }
                        if ((XaCsr & CSR_STOP) != 0) {
                              SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
                        }
                  }

                  /*
                   * Because of the ASIC problem report entry from 21.08.1998 it is
                   * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
                   */
            } while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
                         (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);

            /* Reset the MAC depending on the RstMode */
            if (RstMode == SK_SOFT_RST) {
                  SkMacSoftRst(pAC, IoC, Port);
            }
            else {
                  SkMacHardRst(pAC, IoC, Port);
            }

            /* Disable Force Sync bit and Enable Alloc bit */
            SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
                  TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);

            /* Stop Interval Timer and Limit Counter of Tx Arbiter */
            SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
            SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);

            /* Perform a local reset of the port's Tx path */

            /* Reset the PCI FIFO of the async Tx queue */
            SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
            /* Reset the PCI FIFO of the sync Tx queue */
            SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
            /* Reset the RAM Buffer async Tx queue */
            SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
            /* Reset the RAM Buffer sync Tx queue */
            SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);

            /* Reset Tx MAC FIFO */
            if (pAC->GIni.GIGenesis) {
                  /* Note: MFF_RST_SET does NOT reset the XMAC ! */
                  SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);

                  /* switch Link and Tx LED off, stop the LED counters */
                  /* Link LED is switched off by the RLMT and the Diag itself */
                  SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
            }
            else {
                  /* Reset TX MAC FIFO */
                  SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
            }
      }

      if ((Dir & SK_STOP_RX) != 0) {
            /*
             * The RX Stop Command will not terminate if no buffers
             * are queued in the RxD ring. But it will always reach
             * the Idle state. Therefore we can use this feature to
             * stop the transfer of received packets.
             */
            /* stop the port's receive queue */
            SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);

            i = 100;
            do {
                  /*
                   * Clear packet arbiter timeout to make sure
                   * this loop will terminate
                   */
                  SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_RX1 :
                        PA_CLR_TO_RX2);

                  DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);

                  /* timeout if i==0 (bug fix for #10748) */
                  if (--i == 0) {
                        SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
                              SKERR_HWI_E024MSG);
                        break;
                  }
                  /*
                   * because of the ASIC problem report entry from 21.08.98
                   * it is required to wait until CSR_STOP is reset and
                   * CSR_SV_IDLE is set.
                   */
            } while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);

            /* The path data transfer activity is fully stopped now */

            /* Perform a local reset of the port's Rx path */

             /*   Reset the PCI FIFO of the Rx queue */
            SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
            /* Reset the RAM Buffer receive queue */
            SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);

            /* Reset Rx MAC FIFO */
            if (pAC->GIni.GIGenesis) {

                  SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);

                  /* switch Rx LED off, stop the LED counter */
                  SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
            }
            else {
                  /* Reset Rx MAC FIFO */
                  SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
            }
      }
}     /* SkGeStopPort */


/******************************************************************************
 *
 *    SkGeInit0() - Level 0 Initialization
 *
 * Description:
 *    - Initialize the BMU address offsets
 *
 * Returns:
 *    nothing
 */
static void SkGeInit0(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      int i;
      SK_GEPORT *pPrt;

      for (i = 0; i < SK_MAX_MACS; i++) {
            pPrt = &pAC->GIni.GP[i];

            pPrt->PState = SK_PRT_RESET;
            pPrt->PRxQOff = QOffTab[i].RxQOff;
            pPrt->PXsQOff = QOffTab[i].XsQOff;
            pPrt->PXaQOff = QOffTab[i].XaQOff;
            pPrt->PCheckPar = SK_FALSE;
            pPrt->PIsave = 0;
            pPrt->PPrevShorts = 0;
            pPrt->PLinkResCt = 0;
            pPrt->PAutoNegTOCt = 0;
            pPrt->PPrevRx = 0;
            pPrt->PPrevFcs = 0;
            pPrt->PRxLim = SK_DEF_RX_WA_LIM;
            pPrt->PLinkMode = SK_LMODE_AUTOFULL;
            pPrt->PLinkSpeedCap = SK_LSPEED_CAP_1000MBPS;
            pPrt->PLinkSpeed = SK_LSPEED_1000MBPS;
            pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_UNKNOWN;
            pPrt->PLinkModeConf = SK_LMODE_AUTOSENSE;
            pPrt->PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
            pPrt->PLinkBroken = SK_TRUE; /* See WA code */
            pPrt->PLinkCap = (SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
                        SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
            pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
            pPrt->PFlowCtrlCap = SK_FLOW_MODE_SYM_OR_REM;
            pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
            pPrt->PMSCap = 0;
            pPrt->PMSMode = SK_MS_MODE_AUTO;
            pPrt->PMSStatus = SK_MS_STAT_UNSET;
            pPrt->PAutoNegFail = SK_FALSE;
            pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
            pPrt->PHWLinkUp = SK_FALSE;
      }

      pAC->GIni.GIPortUsage = SK_RED_LINK;

}     /* SkGeInit0*/

#ifdef SK_PCI_RESET

/******************************************************************************
 *
 *    SkGePciReset() - Reset PCI interface
 *
 * Description:
 *    o Read PCI configuration.
 *    o Change power state to 3.
 *    o Change power state to 0.
 *    o Restore PCI configuration.
 *
 * Returns:
 *    0:    Success.
 *    1:    Power state could not be changed to 3.
 */
static int SkGePciReset(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      int         i;
      SK_U16      PmCtlSts;
      SK_U32      Bp1;
      SK_U32      Bp2;
      SK_U16      PciCmd;
      SK_U8 Cls;
      SK_U8 Lat;
      SK_U8 ConfigSpace[PCI_CFG_SIZE];

      /*
       * Note: Switching to D3 state is like a software reset.
       *           Switching from D3 to D0 is a hardware reset.
       *           We have to save and restore the configuration space.
       */
      for (i = 0; i < PCI_CFG_SIZE; i++) {
            SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]);
      }

      /* We know the RAM Interface Arbiter is enabled. */
      SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3);
      SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);

      if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) {
            return(1);
      }

      /* Return to D0 state. */
      SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0);

      /* Check for D0 state. */
      SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);

      if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) {
            return(1);
      }

      /* Check PCI Config Registers. */
      SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd);
      SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls);
      SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1);
      SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2);
      SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat);

      if (PciCmd != 0 || Cls != 0 || (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1 ||
            Lat != 0) {
            return(1);
      }

      /* Restore PCI Config Space. */
      for (i = 0; i < PCI_CFG_SIZE; i++) {
            SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]);
      }

      return(0);
}     /* SkGePciReset */

#endif /* SK_PCI_RESET */

/******************************************************************************
 *
 *    SkGeInit1() - Level 1 Initialization
 *
 * Description:
 *    o Do a software reset.
 *    o Clear all reset bits.
 *    o Verify that the detected hardware is present.
 *      Return an error if not.
 *    o Get the hardware configuration
 *          + Read the number of MACs/Ports.
 *          + Read the RAM size.
 *          + Read the PCI Revision Id.
 *          + Find out the adapters host clock speed
 *          + Read and check the PHY type
 *
 * Returns:
 *    0:    success
 *    5:    Unexpected PHY type detected
 *    6:    HW self test failed
 */
static int SkGeInit1(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      SK_U8 Byte;
      SK_U16      Word;
      SK_U16      CtrlStat;
      SK_U32      FlashAddr;
      int   RetVal;
      int   i;

      RetVal = 0;

      /* save CLK_RUN bits (YUKON-Lite) */
      SK_IN16(IoC, B0_CTST, &CtrlStat);

#ifdef SK_PCI_RESET
      (void)SkGePciReset(pAC, IoC);
#endif /* SK_PCI_RESET */

      /* do the SW-reset */
      SK_OUT8(IoC, B0_CTST, CS_RST_SET);

      /* release the SW-reset */
      SK_OUT8(IoC, B0_CTST, CS_RST_CLR);

      /* reset all error bits in the PCI STATUS register */
      /*
       * Note: PCI Cfg cycles cannot be used, because they are not
       *           available on some platforms after 'boot time'.
       */
      SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);

      SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
      SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
      SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);

      /* release Master Reset */
      SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);

#ifdef CLK_RUN
      CtrlStat |= CS_CLK_RUN_ENA;
#endif /* CLK_RUN */

      /* restore CLK_RUN bits */
      SK_OUT16(IoC, B0_CTST, CtrlStat &
            (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA));

      /* read Chip Identification Number */
      SK_IN8(IoC, B2_CHIP_ID, &Byte);
      pAC->GIni.GIChipId = Byte;

      /* read number of MACs */
      SK_IN8(IoC, B2_MAC_CFG, &Byte);
      pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;

      /* get Chip Revision Number */
      pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);

      /* get diff. PCI parameters */
      SK_IN16(IoC, B0_CTST, &CtrlStat);

      /* read the adapters RAM size */
      SK_IN8(IoC, B2_E_0, &Byte);

      if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {

            pAC->GIni.GIGenesis = SK_TRUE;

            if (Byte == 3) {
                  /* special case: 4 x 64k x 36, offset = 0x80000 */
                  pAC->GIni.GIRamSize = 1024;
                  pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
            }
            else {
                  pAC->GIni.GIRamSize = (int)Byte * 512;
                  pAC->GIni.GIRamOffs = 0;
            }
            /* all GE adapters work with 53.125 MHz host clock */
            pAC->GIni.GIHstClkFact = SK_FACT_53;

            /* set Descr. Poll Timer Init Value to 250 ms */
            pAC->GIni.GIPollTimerVal =
                  SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
      }
      else {
            pAC->GIni.GIGenesis = SK_FALSE;

#ifndef VCPU
            pAC->GIni.GIRamSize = (Byte == 0) ? 128 : (int)Byte * 4;
#else
            pAC->GIni.GIRamSize = 128;
#endif
            pAC->GIni.GIRamOffs = 0;

            /* WA for chip Rev. A */
            pAC->GIni.GIWolOffs = (pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;

            /* get PM Capabilities of PCI config space */
            SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word);

            /* check if VAUX is available */
            if (((CtrlStat & CS_VAUX_AVAIL) != 0) &&
                  /* check also if PME from D3cold is set */
                  ((Word & PCI_PME_D3C_SUP) != 0)) {
                  /* set entry in GE init struct */
                  pAC->GIni.GIVauxAvail = SK_TRUE;
            }

            /* save Flash-Address Register */
            SK_IN32(IoC, B2_FAR, &FlashAddr);

            /* test Flash-Address Register */
            SK_OUT8(IoC, B2_FAR + 3, 0xff);
            SK_IN8(IoC, B2_FAR + 3, &Byte);

            pAC->GIni.GIYukonLite = (SK_BOOL)(Byte != 0);

            /* restore Flash-Address Register */
            SK_OUT32(IoC, B2_FAR, FlashAddr);

            for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
                  /* set GMAC Link Control reset */
                  SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);

                  /* clear GMAC Link Control reset */
                  SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
            }
            /* all YU chips work with 78.125 MHz host clock */
            pAC->GIni.GIHstClkFact = SK_FACT_78;

            pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;  /* 215 ms */
      }

      /* check if 64-bit PCI Slot is present */
      pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);

      /* check if 66 MHz PCI Clock is active */
      pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);

      /* read PCI HW Revision Id. */
      SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
      pAC->GIni.GIPciHwRev = Byte;

      /* read the PMD type */
      SK_IN8(IoC, B2_PMD_TYP, &Byte);
      pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');

      /* read the PHY type */
      SK_IN8(IoC, B2_E_1, &Byte);

      Byte &= 0x0f;     /* the PHY type is stored in the lower nibble */
      for (i = 0; i < pAC->GIni.GIMacsFound; i++) {

            if (pAC->GIni.GIGenesis) {
                  switch (Byte) {
                  case SK_PHY_XMAC:
                        pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
                        break;
                  case SK_PHY_BCOM:
                        pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
                        pAC->GIni.GP[i].PMSCap =
                              SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
                        break;
#ifdef OTHER_PHY
                  case SK_PHY_LONE:
                        pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
                        break;
                  case SK_PHY_NAT:
                        pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
                        break;
#endif /* OTHER_PHY */
                  default:
                        /* ERROR: unexpected PHY type detected */
                        RetVal = 5;
                        break;
                  }
            }
            else {
                  if (Byte == 0) {
                        /* if this field is not initialized */
                        Byte = SK_PHY_MARV_COPPER;
                        pAC->GIni.GICopperType = SK_TRUE;
                  }
                  pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;

                  if (pAC->GIni.GICopperType) {
                        pAC->GIni.GP[i].PLinkSpeedCap = SK_LSPEED_CAP_AUTO |
                              SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
                              SK_LSPEED_CAP_1000MBPS;
                        pAC->GIni.GP[i].PLinkSpeed = SK_LSPEED_AUTO;
                        pAC->GIni.GP[i].PMSCap =
                              SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
                  }
                  else {
                        Byte = SK_PHY_MARV_FIBER;
                  }
            }

            pAC->GIni.GP[i].PhyType = Byte;

            SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
                  ("PHY type: %d  PHY addr: %04x\n", Byte,
                  pAC->GIni.GP[i].PhyAddr));
      }

      /* get Mac Type & set function pointers dependent on */
      if (pAC->GIni.GIGenesis) {
            pAC->GIni.GIMacType = SK_MAC_XMAC;

            pAC->GIni.GIFunc.pFnMacUpdateStats  = SkXmUpdateStats;
            pAC->GIni.GIFunc.pFnMacStatistic    = SkXmMacStatistic;
            pAC->GIni.GIFunc.pFnMacResetCounter = SkXmResetCounter;
            pAC->GIni.GIFunc.pFnMacOverflow           = SkXmOverflowStatus;
      }
      else {
            pAC->GIni.GIMacType = SK_MAC_GMAC;

            pAC->GIni.GIFunc.pFnMacUpdateStats  = SkGmUpdateStats;
            pAC->GIni.GIFunc.pFnMacStatistic    = SkGmMacStatistic;
            pAC->GIni.GIFunc.pFnMacResetCounter = SkGmResetCounter;
            pAC->GIni.GIFunc.pFnMacOverflow           = SkGmOverflowStatus;

#ifdef SPECIAL_HANDLING
            if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
                  /* check HW self test result */
                  SK_IN8(IoC, B2_E_3, &Byte);
                  if ((Byte & B2_E3_RES_MASK) != 0) {
                        RetVal = 6;
                  }
            }
#endif
      }
      return(RetVal);
}     /* SkGeInit1 */


/******************************************************************************
 *
 *    SkGeInit2() - Level 2 Initialization
 *
 * Description:
 *    - start the Blink Source Counter
 *    - start the Descriptor Poll Timer
 *    - configure the MAC-Arbiter
 *    - configure the Packet-Arbiter
 *    - enable the Tx Arbiters
 *    - enable the RAM Interface Arbiter
 *
 * Returns:
 *    nothing
 */
static void SkGeInit2(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      SK_U32      DWord;
      int         i;

      /* start the Descriptor Poll Timer */
      if (pAC->GIni.GIPollTimerVal != 0) {
            if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
                  pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
            }
            SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
            SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
      }

      if (pAC->GIni.GIGenesis) {
            /* start the Blink Source Counter */
            DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;

            SK_OUT32(IoC, B2_BSC_INI, DWord);
            SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);

            /*
             * Configure the MAC Arbiter and the Packet Arbiter.
             * They will be started once and never be stopped.
             */
            SkGeInitMacArb(pAC, IoC);

            SkGeInitPktArb(pAC, IoC);
      }
      else {
            /* start Time Stamp Timer */
            SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
      }

      /* enable the Tx Arbiters */
      for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
            SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
      }

      /* enable the RAM Interface Arbiter */
      SkGeInitRamIface(pAC, IoC);

}     /* SkGeInit2 */

/******************************************************************************
 *
 *    SkGeInit() - Initialize the GE Adapter with the specified level.
 *
 * Description:
 *    Level 0:    Initialize the Module structures.
 *    Level 1:    Generic Hardware Initialization. The IOP/MemBase pointer has
 *                      to be set before calling this level.
 *
 *                o Do a software reset.
 *                o Clear all reset bits.
 *                o Verify that the detected hardware is present.
 *                  Return an error if not.
 *                o Get the hardware configuration
 *                      + Set GIMacsFound with the number of MACs.
 *                      + Store the RAM size in GIRamSize.
 *                      + Save the PCI Revision ID in GIPciHwRev.
 *                o return an error
 *                      if Number of MACs > SK_MAX_MACS
 *
 *                After returning from Level 0 the adapter
 *                may be accessed with IO operations.
 *
 *    Level 2:    start the Blink Source Counter
 *
 * Returns:
 *    0:    success
 *    1:    Number of MACs exceeds SK_MAX_MACS  (after level 1)
 *    2:    Adapter not present or not accessible
 *    3:    Illegal initialization level
 *    4:    Initialization Level 1 Call missing
 *    5:    Unexpected PHY type detected
 *    6:    HW self test failed
 */
int   SkGeInit(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Level)            /* initialization level */
{
      int         RetVal;           /* return value */
      SK_U32      DWord;

      RetVal = 0;
      SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
            ("SkGeInit(Level %d)\n", Level));

      switch (Level) {
      case SK_INIT_DATA:
            /* Initialization Level 0 */
            SkGeInit0(pAC, IoC);
            pAC->GIni.GILevel = SK_INIT_DATA;
            break;

      case SK_INIT_IO:
            /* Initialization Level 1 */
            RetVal = SkGeInit1(pAC, IoC);
            if (RetVal != 0) {
                  break;
            }

            /* check if the adapter seems to be accessible */
            SK_OUT32(IoC, B2_IRQM_INI, 0x11335577L);
            SK_IN32(IoC, B2_IRQM_INI, &DWord);
            SK_OUT32(IoC, B2_IRQM_INI, 0L);

            if (DWord != 0x11335577L) {
                  RetVal = 2;
                  break;
            }

            /* check if the number of GIMacsFound matches SK_MAX_MACS */
            if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
                  RetVal = 1;
                  break;
            }

            /* Level 1 successfully passed */
            pAC->GIni.GILevel = SK_INIT_IO;
            break;

      case SK_INIT_RUN:
            /* Initialization Level 2 */
            if (pAC->GIni.GILevel != SK_INIT_IO) {
#ifndef SK_DIAG
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
#endif /* !SK_DIAG */
                  RetVal = 4;
                  break;
            }
            SkGeInit2(pAC, IoC);

            /* Level 2 successfully passed */
            pAC->GIni.GILevel = SK_INIT_RUN;
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
            RetVal = 3;
            break;
      }

      return(RetVal);
}     /* SkGeInit */


/******************************************************************************
 *
 *    SkGeDeInit() - Deinitialize the adapter
 *
 * Description:
 *    All ports of the adapter will be stopped if not already done.
 *    Do a software reset and switch off all LEDs.
 *
 * Returns:
 *    nothing
 */
void SkGeDeInit(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC)        /* IO context */
{
      int   i;
      SK_U16      Word;

#ifndef VCPU
      /* ensure I2C is ready */
      SkI2cWaitIrq(pAC, IoC);
#endif

      /* stop all current transfer activity */
      for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
            if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
                  pAC->GIni.GP[i].PState != SK_PRT_RESET) {

                  SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
            }
      }

      /* Reset all bits in the PCI STATUS register */
      /*
       * Note: PCI Cfg cycles cannot be used, because they are not
       *     available on some platforms after 'boot time'.
       */
      SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);

      SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
      SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
      SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);

      /* do the reset, all LEDs are switched off now */
      SK_OUT8(IoC, B0_CTST, CS_RST_SET);
}     /* SkGeDeInit */


/******************************************************************************
 *
 *    SkGeInitPort()    Initialize the specified port.
 *
 * Description:
 *    PRxQSize, PXSQSize, and PXAQSize has to be
 *    configured for the specified port before calling this function.
 *  The descriptor rings has to be initialized too.
 *
 *    o (Re)configure queues of the specified port.
 *    o configure the MAC of the specified port.
 *    o put ASIC and MAC(s) in operational mode.
 *    o initialize Rx/Tx and Sync LED
 *    o initialize RAM Buffers and MAC FIFOs
 *
 *    The port is ready to connect when returning.
 *
 * Note:
 *    The MAC's Rx and Tx state machine is still disabled when returning.
 *
 * Returns:
 *    0:    success
 *    1:    Queue size initialization error. The configured values
 *          for PRxQSize, PXSQSize, or PXAQSize are invalid for one
 *          or more queues. The specified port was NOT initialized.
 *          An error log entry was generated.
 *    2:    The port has to be stopped before it can be initialized again.
 */
int SkGeInitPort(
SK_AC *pAC,       /* adapter context */
SK_IOC      IoC,        /* IO context */
int         Port)       /* Port to configure */
{
      SK_GEPORT *pPrt;

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

      if (SkGeCheckQSize(pAC, Port) != 0) {
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
            return(1);
      }

      if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
            return(2);
      }

      /* configuration ok, initialize the Port now */

      if (pAC->GIni.GIGenesis) {
            /* initialize Rx, Tx and Link LED */
            /*
             * If 1000BT Phy needs LED initialization than swap
             * LED and XMAC initialization order
             */
            SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
            SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
            /* The Link LED is initialized by RLMT or Diagnostics itself */

            SkXmInitMac(pAC, IoC, Port);
      }
      else {

            SkGmInitMac(pAC, IoC, Port);
      }

      /* do NOT initialize the Link Sync Counter */

      SkGeInitMacFifo(pAC, IoC, Port);

      SkGeInitRamBufs(pAC, IoC, Port);

      if (pPrt->PXSQSize != 0) {
            /* enable Force Sync bit if synchronous queue available */
            SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
      }

      SkGeInitBmu(pAC, IoC, Port);

      /* mark port as initialized */
      pPrt->PState = SK_PRT_INIT;

      return(0);
}     /* SkGeInitPort */

#endif /* CONFIG_SK98 */

Generated by  Doxygen 1.6.0   Back to index