diff options
Diffstat (limited to 'drivers/net/sk98lin/skgeinit.c')
| -rw-r--r-- | drivers/net/sk98lin/skgeinit.c | 2372 | 
1 files changed, 2372 insertions, 0 deletions
| diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c new file mode 100644 index 000000000..a18dc0a48 --- /dev/null +++ b/drivers/net/sk98lin/skgeinit.c @@ -0,0 +1,2372 @@ +/****************************************************************************** + * + * 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 */ |