/******************************************************************************
 *
 * Name:	skgeinit.c
 * Project:	Gigabit Ethernet Adapters, Common Modules
 * Version:	$Revision: 1.97 $
 * Date:	$Date: 2003/10/02 16:45:31 $
 * Purpose:	Contains functions to initialize the adapter
 *
 ******************************************************************************/

/******************************************************************************
 *
 *	(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"

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

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

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

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}
};

struct s_Config {
	char	ScanString[8];
	SK_U32	Value;
};

static struct s_Config OemConfig = {
	{'O','E','M','_','C','o','n','f'},
#ifdef SK_OEM_CONFIG
	OEM_CONFIG_VALUE,
#else
	0,
#endif
};

/******************************************************************************
 *
 *	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 = (SK_U32)(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 */


#if (!defined(SK_SLIM) || defined(GENESIS))
/******************************************************************************
 *
 *	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 */
#endif	/* !SK_SLIM || GENESIS */


/******************************************************************************
 *
 *	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	SK_FAR *pPrt,		/* port index */
int			QuSize,				/* size of the queue to configure in kB */
SK_U32		SK_FAR *StartVal,	/* start value for address calculation */
SK_U32		SK_FAR *QuStartAddr,/* start addr to calculate */
SK_U32		SK_FAR *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	i;
	int	Rtv;
	int	Rtv2;
	SK_U32	StartAddr;
#ifndef SK_SLIM
	int	UsedMem;	/* total memory used (max. found ports) */
#endif	

	Rtv = 0;
	
#ifndef SK_SLIM

	UsedMem = 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);
	}
#endif	/* !SK_SLIM */

	/* 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 */


#ifdef GENESIS
/******************************************************************************
 *
 *	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 */
#endif /* GENESIS */


/******************************************************************************
 *
 *	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
	 */
	
#ifdef GENESIS
	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);
		}
	}
#endif /* GENESIS */
	
#ifdef YUKON
	if (pAC->GIni.GIYukon) {
		/* set Rx GMAC FIFO Flush Mask */
		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
		
		Word = (SK_U16)GMF_RX_CTRL_DEF;

		/* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
		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); */
	}
#endif /* YUKON */

}	/* SkGeInitMacFifo */

#ifdef	SK_LNK_SYNC_CNT
/******************************************************************************
 *
 *	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*/
#endif	/* SK_LNK_SYNC_CNT */

#if defined(SK_DIAG) || defined(SK_CFG_SYNC)
/******************************************************************************
 *
 *	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 */
#endif /* SK_DIAG || SK_CFG_SYNC*/


/******************************************************************************
 *
 *	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.GIYukon) {
				/* 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
 */
static 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, (SK_U16)((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 */
#ifdef GENESIS
		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);
		}
#endif /* GENESIS */
	
#ifdef YUKON
		if (pAC->GIni.GIYukon) {
			/* Reset TX MAC FIFO */
			SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
		}
#endif /* YUKON */
	}

	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, (SK_U16)((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 */
#ifdef GENESIS
		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);
		}
#endif /* GENESIS */
	
#ifdef YUKON
		if (pAC->GIni.GIYukon) {
			/* Reset Rx MAC FIFO */
			SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
		}
#endif /* YUKON */
	}
}	/* 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_U8)SK_LMODE_AUTOFULL;
		pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS;
		pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS;
		pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN;
		pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE;
		pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
		pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
			SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
		pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
		pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
		pPrt->PMSCap = 0;
		pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO;
		pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET;
		pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN;
		pPrt->PAutoNegFail = SK_FALSE;
		pPrt->PHWLinkUp = SK_FALSE;
		pPrt->PLinkBroken = SK_TRUE; /* See WA code */
		pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
		pPrt->PMacColThres = TX_COL_DEF;
		pPrt->PMacJamLen = TX_JAM_LEN_DEF;
		pPrt->PMacJamIpgVal	= TX_JAM_IPG_DEF;
		pPrt->PMacJamIpgData = TX_IPG_JAM_DEF;
		pPrt->PMacIpgData = IPG_DATA_DEF;
		pPrt->PMacLimit4 = SK_FALSE;
	}

	pAC->GIni.GIPortUsage = SK_RED_LINK;
	pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value;
	pAC->GIni.GIValIrqMask = IS_ALL_MSK;

}	/* SkGeInit0*/


/******************************************************************************
 *
 *	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	DWord;
	int	RetVal;
	int	i;

	RetVal = 0;

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

	/* 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), (SK_U16)(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, (SK_U16)(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);
	
	pAC->GIni.GIGenesis = SK_FALSE;
	pAC->GIni.GIYukon = SK_FALSE;
	pAC->GIni.GIYukonLite = SK_FALSE;

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

		pAC->GIni.GIGenesis = SK_TRUE;

		if (Byte == (SK_U8)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;
	}
#endif /* GENESIS */
	
#ifdef YUKON
	if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) {
		
		pAC->GIni.GIYukon = SK_TRUE;
		
		pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4;
		
		pAC->GIni.GIRamOffs = 0;
		
		/* WA for chip Rev. A */
		pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON &&
			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;
		}
		
		if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) {
			/* this is Rev. A1 */
			pAC->GIni.GIYukonLite = SK_TRUE;
		}
		else {
			/* save Flash-Address Register */
			SK_IN32(IoC, B2_FAR, &DWord);

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

			if (Byte != 0) {
				/* this is Rev. A0 */
				pAC->GIni.GIYukonLite = SK_TRUE;

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

		/* switch power to VCC (WA for VAUX problem) */
		SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
			PC_VAUX_OFF | PC_VCC_ON));

		/* read the Interrupt source */
		SK_IN32(IoC, B0_ISRC, &DWord);
		
		if ((DWord & IS_HW_ERR) != 0) {
			/* read the HW Error Interrupt source */
			SK_IN32(IoC, B0_HWE_ISRC, &DWord);
			
			if ((DWord & IS_IRQ_SENSOR) != 0) {
				/* disable HW Error IRQ */
				pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
			}
		}
		
		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 */
	}
#endif /* YUKON */

	/* 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++) {
		
#ifdef GENESIS
		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_U8)(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;
			}
		}
#endif /* GENESIS */
	
#ifdef YUKON
		if (pAC->GIni.GIYukon) {
			
			if (Byte < (SK_U8)SK_PHY_MARV_COPPER) {
				/* if this field is not initialized */
				Byte = (SK_U8)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_U8)(SK_LSPEED_CAP_AUTO |
					SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
					SK_LSPEED_CAP_1000MBPS);
				
				pAC->GIni.GP[i].PLinkSpeed = (SK_U8)SK_LSPEED_AUTO;
				
				pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
					SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
			}
			else {
				Byte = (SK_U8)SK_PHY_MARV_FIBER;
			}
		}
#endif /* YUKON */
		
		pAC->GIni.GP[i].PhyType = (int)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 */
#ifdef GENESIS
	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;
	}
#endif /* GENESIS */
	
#ifdef YUKON
	if (pAC->GIni.GIYukon) {
		
		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) {
				RetVal = 6;
			}
		}
#endif
	}
#endif /* YUKON */
	
	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 */
{
#ifdef GENESIS
	SK_U32	DWord;
#endif /* GENESIS */
	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);
	}

#ifdef GENESIS
	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);
	}
#endif /* GENESIS */
	
#ifdef YUKON
	if (pAC->GIni.GIYukon) {
		/* start Time Stamp Timer */
		SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
	}
#endif /* YUKON */

	/* 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, SK_TEST_VAL);
		SK_IN32(IoC, B2_IRQM_INI, &DWord);
		SK_OUT32(IoC, B2_IRQM_INI, 0L);
		
		if (DWord != SK_TEST_VAL) {
			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;

#if (!defined(SK_SLIM) && !defined(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), (SK_U16)(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);
	
	pAC->GIni.GILevel = SK_INIT_DATA;
}	/* 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 */

#ifdef GENESIS
	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);
	}
#endif /* GENESIS */
	
#ifdef YUKON
	if (pAC->GIni.GIYukon) {

		SkGmInitMac(pAC, IoC, Port);
	}
#endif /* YUKON */
	
	/* 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 */
