patch-2.2.14 linux/drivers/net/sk98lin/skxmac2.c

Next file: linux/drivers/net/sktr.c
Previous file: linux/drivers/net/sk98lin/skvpd.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c
@@ -0,0 +1,2047 @@
+/******************************************************************************
+ *
+ * Name:	skxmac2.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.49 $
+ * Date:	$Date: 1999/11/22 08:12:13 $
+ * Purpose:	Contains functions to initialize the XMAC II
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further information.
+ *
+ *	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: skxmac2.c,v $
+ *	Revision 1.49  1999/11/22 08:12:13  malthoff
+ *	Add workaround for power consumption feature of Bcom C0 chip.
+ *	
+ *	Revision 1.48  1999/11/16 08:39:01  malthoff
+ *	Fix: MDIO preamble suppression is port dependend.
+ *	
+ *	Revision 1.47  1999/08/27 08:55:35  malthoff
+ *	1000BT: Optimizing MDIO transfer by oppressing MDIO preamble.
+ *	
+ *	Revision 1.46  1999/08/13 11:01:12  malthoff
+ *	Fix for 1000BT: pFlowCtrlMode was not set correctly.
+ *	
+ *	Revision 1.45  1999/08/12 19:18:28  malthoff
+ *	1000BT Fixes: Do not owerwrite XM_MMU_CMD.
+ *	Do not execute BCOM A1 workaround for B1 chips.
+ *	Fix pause frame setting.
+ *	Always set PHY_B_AC_TX_TST in PHY_BCOM_AUX_CTRL.
+ *	
+ *	Revision 1.44  1999/08/03 15:23:48  cgoos
+ *	Fixed setting of PHY interrupt mask in half duplex mode.
+ *	
+ *	Revision 1.43  1999/08/03 15:22:17  cgoos
+ *	Added some debug output.
+ *	Disabled XMac GP0 interrupt for external PHYs.
+ *	
+ *	Revision 1.42  1999/08/02 08:39:23  malthoff
+ *	BCOM PHY: TX LED: To get the mono flop behaviour it is required
+ *	to set the LED Traffic Mode bit in PHY_BCOM_P_EXT_CTRL.
+ *	
+ *	Revision 1.41  1999/07/30 06:54:31  malthoff
+ *	Add temp. workarounds for the BCOM Phy revision A1.
+ *	
+ *	Revision 1.40  1999/06/01 07:43:26  cgoos
+ *	Changed Link Mode Status in SkXmAutoNegDone... from FULL/HALF to
+ *	AUTOFULL/AUTOHALF.
+ *	
+ *	Revision 1.39  1999/05/19 07:29:51  cgoos
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.38  1999/04/08 14:35:10  malthoff
+ *	Add code for enabling signal detect. Enabling signal
+ *	detect is disabled.
+ *	
+ *	Revision 1.37  1999/03/12 13:42:54  malthoff
+ *	Add: Jumbo Frame Support.
+ *	Add: Receive modes SK_LENERR_OK_ON/OFF and
+ *	SK_BIG_PK_OK_ON/OFF in SkXmSetRxCmd().
+ *	
+ *	Revision 1.36  1999/03/08 10:10:55  gklug
+ *	fix: AutoSensing did switch to next mode even if LiPa indicated offline
+ *
+ *	Revision 1.35  1999/02/22 15:16:41  malthoff
+ *	Remove some compiler warnings.
+ *
+ *	Revision 1.34  1999/01/22 09:19:59  gklug
+ *	fix: Init DupMode and InitPauseMd are now called in RxTxEnable
+ *
+ *	Revision 1.33  1998/12/11 15:19:11  gklug
+ *	chg: lipa autoneg stati
+ *	chg: debug messages
+ *	chg: do NOT use spurious XmIrq
+ *
+ *	Revision 1.32  1998/12/10 11:08:44  malthoff
+ *	bug fix: pAC has been used for IOs in SkXmHardRst().
+ *	SkXmInitPhy() is also called for the Diag in SkXmInitMac().
+ *
+ *	Revision 1.31  1998/12/10 10:39:11  gklug
+ *	fix: do 4 RESETS of the XMAC at the beginning
+ *	fix: dummy read interrupt source register BEFORE initializing the Phy
+ *	add: debug messages
+ *	fix: Linkpartners autoneg capability cannot be shown by TX_PAGE interrupt
+ *
+ *	Revision 1.30  1998/12/07 12:18:32  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *
+ *	Revision 1.29  1998/12/07 07:12:29  gklug
+ *	fix: if page is received the link is  down.
+ *
+ *	Revision 1.28  1998/12/01 10:12:47  gklug
+ *	chg: if spurious IRQ from XMAC encountered, save it
+ *
+ *	Revision 1.27  1998/11/26 07:33:38  gklug
+ *	add: InitPhy call is now in XmInit function
+ *
+ *	Revision 1.26  1998/11/18 13:38:24  malthoff
+ *	'Imsk' is also unused in SkXmAutoNegDone.
+ *
+ *	Revision 1.25  1998/11/18 13:28:01  malthoff
+ *	Remove unused variable 'Reg' in SkXmAutoNegDone().
+ *
+ *	Revision 1.24  1998/11/18 13:18:45  gklug
+ *	add: workaround for xmac errata #1
+ *	add: detect Link Down also when Link partner requested config
+ *	chg: XMIrq is only used when link is up
+ *
+ *	Revision 1.23  1998/11/04 07:07:04  cgoos
+ *	Added function SkXmRxTxEnable.
+ *
+ *	Revision 1.22  1998/10/30 07:35:54  gklug
+ *	fix: serve LinkDown interrupt when link is already down
+ *
+ *	Revision 1.21  1998/10/29 15:32:03  gklug
+ *	fix: Link Down signaling
+ *
+ *	Revision 1.20  1998/10/29 11:17:27  gklug
+ *	fix: AutoNegDone bug
+ *
+ *	Revision 1.19  1998/10/29 10:14:43  malthoff
+ *	Add endainesss comment for reading/writing MAC addresses.
+ *
+ *	Revision 1.18  1998/10/28 07:48:55  cgoos
+ *	Fix: ASS somtimes signaled although link is up.
+ *
+ *	Revision 1.17  1998/10/26 07:55:39  malthoff
+ *	Fix in SkXmInitPauseMd(): Pause Mode
+ *	was disabled and not enabled.
+ *	Fix in SkXmAutoNegDone(): Checking Mode bits
+ *	always failed, becaues of some missing braces.
+ *
+ *	Revision 1.16  1998/10/22 09:46:52  gklug
+ *	fix SysKonnectFileId typo
+ *
+ *	Revision 1.15  1998/10/21 05:51:37  gklug
+ *	add: para DoLoop to InitPhy function for loopback set-up
+ *
+ *	Revision 1.14  1998/10/16 10:59:23  malthoff
+ *	Remove Lint warning for dummy reads.
+ *
+ *	Revision 1.13  1998/10/15 14:01:20  malthoff
+ *	Fix: SkXmAutoNegDone() is (int) but does not return a value.
+ *
+ *	Revision 1.12  1998/10/14 14:45:04  malthoff
+ *	Remove SKERR_SIRQ_E0xx and SKERR_SIRQ_E0xxMSG by
+ *	SKERR_HWI_Exx and SKERR_HWI_E0xxMSG to be independant
+ *	from the Sirq module.
+ *
+ *	Revision 1.11  1998/10/14 13:59:01  gklug
+ *	add: InitPhy function
+ *
+ *	Revision 1.10  1998/10/14 11:20:57  malthoff
+ *	Make SkXmAutoNegDone() public, because it's
+ *	used in diagnostics, too.
+ *	The Link Up event to the RLMT is issued in
+ *	SkXmIrq(). SkXmIrq() is not available in
+ *	diagnostics. Use PHY_READ when reading
+ *	PHY registers.
+ *
+ *	Revision 1.9  1998/10/14 05:50:10  cgoos
+ *	Added definition for Para.
+ *
+ *	Revision 1.8  1998/10/14 05:41:28  gklug
+ *	add: Xmac IRQ
+ *	add: auto negotiation done function
+ *
+ *	Revision 1.7  1998/10/09 06:55:20  malthoff
+ *	The configuration of the XMACs Tx Request Threshold
+ *	depends from the drivers port usage now. The port
+ *	usage is configured in GIPortUsage.
+ *
+ *	Revision 1.6  1998/10/05 07:48:00  malthoff
+ *	minor changes
+ *
+ *	Revision 1.5  1998/10/01 07:03:54  gklug
+ *	add: dummy function for XMAC ISR
+ *
+ *	Revision 1.4  1998/09/30 12:37:44  malthoff
+ *	Add SkXmSetRxCmd() and related code.
+ *
+ *	Revision 1.3  1998/09/28 13:26:40  malthoff
+ *	Add SkXmInitMac(), SkXmInitDupMd(), and SkXmInitPauseMd()
+ *
+ *	Revision 1.2  1998/09/16 14:34:21  malthoff
+ *	Add SkXmClrExactAddr(), SkXmClrSrcCheck(),
+ *	SkXmClrHashAddr(), SkXmFlushTxFifo(),
+ *	SkXmFlushRxFifo(), and SkXmHardRst().
+ *	Finish Coding of SkXmSoftRst().
+ *	The sources may be compiled now.
+ *
+ *	Revision 1.1  1998/09/04 10:05:56  malthoff
+ *	Created.
+ *
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/xmac_ii.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+/* typedefs *******************************************************************/
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skxmac2.c,v 1.49 1999/11/22 08:12:13 malthoff Exp $ (C) SK ";
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+	int	PhyReg;		/* Phy register */
+	SK_U16	PhyVal;		/* Value to write */
+} BCOM_HACK;
+
+BCOM_HACK BcomRegA1Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+BCOM_HACK BcomRegC0Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
+ { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+
+/* function prototypes ********************************************************/
+static void	SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+
+/******************************************************************************
+ *
+ *	SkXmSetRxCmd() - Modify the value of the XMACs Rx Command Register
+ *
+ * Description:
+ *	The features
+ *	 o FCS stripping,			SK_STRIP_FCS_ON/OFF
+ *	 o pad byte stripping,			SK_STRIP_PAD_ON/OFF
+ *	 o don't set XMR_FS_ERR in frame	SK_LENERR_OK_ON/OFF
+ *	   status for inrange length error
+ *	   frames, and
+ *	 o don't set XMR_FS_ERR in frame	SK_BIG_PK_OK_ON/OFF
+ *	   status for frames > 1514 bytes
+ *
+ *	for incomming packets may be enabled/disabled by this function.
+ *	Additional modes may be added later.
+ *	Multiple modes can be enabled/disabled at the same time.
+ *	The new configuration is stored into the HWAC port configuration
+ *	and is written to the Receive Command register immediatlely.
+ *	The new configuration is saved over any SkGePortStop() and
+ *	SkGeInitPort() calls. The configured value will be overwritten
+ *	when SkGeInit(Level 0) is executed.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* The XMAC to handle with belongs to this Port */
+int	Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+				SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+	SK_GEPORT *pPrt;
+	SK_U16	OldRxMode;
+
+	pPrt = &pAC->GIni.GP[Port];
+	OldRxMode = pPrt->PRxCmd;
+
+	switch(Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+	case SK_STRIP_FCS_ON:
+		pPrt->PRxCmd |= XM_RX_STRIP_FCS;
+		break;
+	case SK_STRIP_FCS_OFF:
+		pPrt->PRxCmd &= ~XM_RX_STRIP_FCS;
+		break;
+	}
+
+	switch(Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+	case SK_STRIP_PAD_ON:
+		pPrt->PRxCmd |= XM_RX_STRIP_PAD;
+		break;
+	case SK_STRIP_PAD_OFF:
+		pPrt->PRxCmd &= ~XM_RX_STRIP_PAD;
+		break;
+	}
+
+	switch(Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+	case SK_LENERR_OK_ON:
+		pPrt->PRxCmd |= XM_RX_LENERR_OK;
+		break;
+	case SK_LENERR_OK_OFF:
+		pPrt->PRxCmd &= ~XM_RX_LENERR_OK;
+		break;
+	}
+
+	switch(Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+	case SK_BIG_PK_OK_ON:
+		pPrt->PRxCmd |= XM_RX_BIG_PK_OK;
+		break;
+	case SK_BIG_PK_OK_OFF:
+		pPrt->PRxCmd &= ~XM_RX_BIG_PK_OK;
+		break;
+	}
+
+	/* Write the new mode to the receive command register if required */
+	if (OldRxMode != pPrt->PRxCmd) {
+		XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ *	All Exact Match Address registers of the XMAC 'Port' will be
+ *	cleared starting with 'StartNum' up to (and including) the
+ *	Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmClrExactAddr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* The XMAC to handle with belongs to this Port */
+int	StartNum,	/* Begin with this Address Register Index (0..15) */
+int	StopNum)	/* Stop after finished with this Register Idx (0..15) */
+{
+	int	i;
+	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+
+	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+		StartNum > StopNum) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+		return;
+	}
+
+	for (i = StartNum; i <= StopNum; i++) {
+		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrSrcCheck() - Clear Source Check Address Register
+ *
+ * Description:
+ *	The Source Check Address Register of the XMAC 'Port' number
+ *	will be cleared.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmClrSrcCheck(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+
+	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrHashAddr() - Clear Hash Address Registers
+ *
+ * Description:
+ *	The Hash Address Register of the XMAC 'Port' will be cleared.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmClrHashAddr(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[4] = { 0x0000, 0x0000, 0x0000, 0x0000 };
+
+	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+}
+
+/******************************************************************************
+ *
+ *	SkXmFlushTxFifo() - Flush the XMACs transmit FIFO
+ *
+ * Description:
+ *	Flush the transmit FIFO of the XMAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmFlushTxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+	MdReg |= XM_MD_FTF;
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+}
+
+/******************************************************************************
+ *
+ *	SkXmFlushRxFifo() - Flush the XMACs receive FIFO
+ *
+ * Description:
+ *	Flush the receive FIFO of the XMAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmFlushRxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+	MdReg |= XM_MD_FRF;
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+}
+
+/******************************************************************************
+ *
+ *	SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ *	The PHY registers should not be destroyed during this
+ *	kind of software reset. Therefore the XMAC Software Reset
+ *	(XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ *	The software reset is done by
+ *		- disabling the Rx and Tx state maschine,
+ *		- reseting the statistics module,
+ *		- clear all other significant XMAC Mode,
+ *		  Command, and Control Registers
+ *		- clearing the Hash Register and the
+ *		  Exact Match Address registers, and
+ *		- flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ *	Another requirement when stopping the XMAC is to
+ *	avoid sending corrupted frames on the network.
+ *	Disabling the Tx state maschine will NOT interrupt
+ *	the currently transmitted frame. But we must take care
+ *	that the tx FIFO is cleared AFTER the current frame
+ *	is complete sent to the network.
+ *
+ *	It takes about 12ns to send a frame with 1538 bytes.
+ *	One PCI clock goes at least 15ns (66MHz). Therefore
+ *	after reading XM_GP_PORT back, we are sure that the
+ *	transmitter is disabled AND idle. And this means
+ *	we may flush the transmit FIFO now.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* port to stop (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16	Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* disable the receiver and transmitter */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX|XM_MMU_ENA_TX));
+
+	/* reset the statistics module */
+	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+	/*
+	 * clear all other significant XMAC Mode,
+	 * Command, and Control Registers
+	 */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);		/* disable all IRQs */
+	XM_OUT32(IoC, Port, XM_MODE, 0x00000000);	/* clear Mode Reg */
+	XM_OUT16(IoC, Port, XM_TX_CMD, 0x0000);		/* reset TX CMD Reg */
+	XM_OUT16(IoC, Port, XM_RX_CMD, 0x0000);		/* reset RX CMD Reg */
+	
+	/* disable all PHY IRQs */
+	switch (pAC->GIni.GP[Port].PhyType) {
+		case SK_PHY_BCOM:
+			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
+				0xffff);
+			break;
+		case SK_PHY_LONE:
+			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
+				0x0);
+			break;
+		case SK_PHY_NAT:
+			/* todo: National
+			 PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
+				0xffff); */
+			break;
+	}
+
+	/* clear the Hash Register */
+	SkXmClrHashAddr(pAC, IoC, Port);
+
+	/* clear the Exact Match Address registers */
+	SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+	SkXmClrSrcCheck(pAC, IoC, Port);
+
+	/* flush the XMAC's Rx and Tx FIFOs */
+	SkXmFlushTxFifo(pAC, IoC, Port);
+	SkXmFlushRxFifo(pAC, IoC, Port);
+
+	pAC->GIni.GP[Port].PState = SK_PRT_STOP;
+}
+
+/******************************************************************************
+ *
+ *	SkXmHardRst() - Do a XMAC hardware reset
+ *
+ * Description:
+ *	The XMAC of the specified 'Port' and all connected devices
+ *	(PHY and SERDES) will receive a reset signal on its *Reset
+ *	pins.
+ *	External PHYs must be reset be clearing a bit in the GPIO
+ *	register (Timing requirements: Broadcom: 400ns, Level One:
+ *	none, National: 80ns).
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* port to stop (MAC_1 + n) */
+{
+	SK_U16	Word;
+	int	i;
+	SK_U32	Reg;
+
+	for (i=0; i<4; i++) {
+		/* TX_MFF_CTRL1 is a 32 bit register but only the lowest 16 */
+		/* bit contains buttoms to press */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_CLR_MAC_RST);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_SET_MAC_RST);
+		do {
+			SK_IN16(IoC,MR_ADDR(Port,TX_MFF_CTRL1), &Word);
+		} while ((Word & MFF_SET_MAC_RST) == 0);
+	}
+	if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+		/* reset external PHY */
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+		if (Port == 0) {
+			Reg |= GP_DIR_0; /* set to output */
+			Reg &= ~GP_IO_0;
+		}
+		else {
+			Reg |= GP_DIR_2; /* set to output */
+			Reg &= ~GP_IO_2;
+		}
+		SK_OUT32(IoC, B2_GP_IO, Reg);
+
+		/* short delay */
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+	}
+
+	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ *	Initialize all the XMAC of the specified port.
+ *	The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The XMACs Rx and Tx state machine is still disabled when
+ *	returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+	SK_U16	SWord;
+	int	i;
+	SK_U32	Reg;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+		if (SWord & (SK_U16) MFF_SET_MAC_RST) {
+			/* PState does not match HW state */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006,
+				SKERR_HWI_E006MSG);
+			/* correct it */
+			pPrt->PState = SK_PRT_RESET;
+		}
+	}
+	if (pPrt->PState == SK_PRT_RESET) {
+		/*
+		 * clear HW reset
+		 * Note: The SW reset is self clearing, therefore there is
+		 *	 nothing to do here.
+		 */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_CLR_MAC_RST);
+		
+		/*
+		 * clear PHY reset
+		 */
+		if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+			SK_IN32(IoC, B2_GP_IO, &Reg);
+			if (Port == 0) {
+				Reg |= GP_DIR_0; /* set to output */
+				Reg |= GP_IO_0;
+			}
+			else {
+				Reg |= GP_DIR_2; /* set to output */
+				Reg |= GP_IO_2;
+			}
+			SK_OUT32(IoC, B2_GP_IO, Reg);
+
+			/* enable GMII interface */
+			XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+
+			/* optimize MDIO transfer by oppressing preamble */
+			XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+			XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+			/* Workaround BCOM Errata for the A1 type */
+			/* Write magic patterns to reserved registers */
+			PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord);
+			if (SWord == 0x6041) {
+				i = 0;
+				while (BcomRegA1Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port,
+						BcomRegA1Hack[i].PhyReg,
+						BcomRegA1Hack[i].PhyVal);
+					i++;
+				}
+			}
+			/* Workaround BCOM Errata for the C0 type */
+			/* Write magic patterns to reserved registers */
+			if (SWord == 0x6044) {
+				i = 0;
+				while (BcomRegC0Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port,
+						BcomRegC0Hack[i].PhyReg,
+						BcomRegC0Hack[i].PhyVal);
+					i++;
+				}
+			}
+
+			/*
+			 * PHY LED initialization is performed in
+			 * SkGeXmitLED() (but not here).
+			 */
+		}
+
+		/* Dummy read the Interrupt source register */
+		XM_IN16(IoC, Port, XM_ISRC, &SWord);
+		
+		/*
+		 * The autonegotiation process starts immediately after
+		 * clearing the reset. Autonegotiation process should be
+		 * started by the SIRQ, therefore stop it here immediately.
+		 */
+		SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
+
+#if 0
+		/* temp. code: enable signal detect */
+		/* WARNING: do not override GMII setting above */
+		XM_OUT16(pAC, Port, XM_HW_CFG, XM_HW_COM4SIG);
+#endif
+	}
+
+	/*
+	 * configure the XMACs Station Address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B
+	 */
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independant. Remember this when changing.
+		 */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+		XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
+	}
+
+	/* Tx Inter Packet Gap (XM_TX_IPG):	use default */
+	/* Tx High Water Mark (XM_TX_HI_WM):	use default */
+	/* Tx Low Water Mark (XM_TX_LO_WM):	use default */
+	/* Host Request Threshold (XM_HT_THR):	use default */
+	/* Rx Request Threshold (XM_RX_THR):	use default */
+	/* Rx Low Water Mark (XM_RX_LO_WM):	use default */
+
+	/* configure Rx High Water Mark (XM_RX_HI_WM) */
+	XM_OUT16(IoC, Port, XM_RX_HI_WM, 0x05aa);
+
+	if (pAC->GIni.GIMacsFound > 1) {
+		switch (pAC->GIni.GIPortUsage) {
+		case SK_RED_LINK:
+			/* Configure Tx Request Threshold for red. link */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_REDL);
+			break;
+		case SK_MUL_LINK:
+			/* Configure Tx Request Threshold for load bal. */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_MULL);
+			break;
+		case SK_JUMBO_LINK:
+			/* Configure Tx Request Threshold for jumbo frames */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_JUMBO);
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014,
+				SKERR_HWI_E014MSG);
+			break;
+		}
+	}
+	else {
+		/* Configure Tx Request Threshold for single port */
+		XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_SL);
+	}
+
+	/*
+	 * setup register defaults for the Rx Command Register
+	 *	- Enable Automatic Frame Padding on Tx side
+	 */
+	XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+	/*
+	 * setup register defaults for the Rx Command Register,
+	 * program value of PRxCmd
+	 */
+	XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+
+	/*
+	 * setup register defaults for the Mode Register
+	 *	- Don't strip error frames to avoid Store & Forward
+	 *	  on the rx side.
+	 *	- Enable 'Check Station Address' bit
+	 *	- Enable 'Check Address Array' bit
+	 */
+	XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);
+
+	/*
+	 * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Rx OK Low CntOv'
+	 *	  and 'Octets Rx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+	/*
+	 * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Tx OK Low CntOv'
+	 *	  and 'Octets Tx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+	/*
+	 * Do NOT init XMAC interrupt mask here.
+	 * All interrupts remain disable until link comes up!
+	 */
+	pPrt->PState = SK_PRT_INIT;
+
+	/*
+	 * Any additional configuration changes may be done now.
+	 * The last action is to enable the rx and tx state machine.
+	 * This should be done after the autonegotiation process
+	 * has been completed successfully.
+	 */
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ *	This function initilaizes the XMACs Duplex Mode.
+ *	It should be called after successfully finishing
+ *	the Autonegotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitDupMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	switch (pAC->GIni.GP[Port].PLinkModeStatus) {
+	case SK_LMODE_STAT_AUTOHALF:
+	case SK_LMODE_STAT_HALF:
+		/* Configuration Actions for Half Duplex Mode */
+		/*
+		 * XM_BURST = default value. We are propable not quick
+		 * 	enough at the 'XMAC' bus to burst 8kB.
+		 *	The XMAC stopps bursting if no transmit frames
+		 *	are available or the burst limit is exceeded.
+		 */
+		/* XM_TX_RT_LIM = default value (15) */
+		/* XM_TX_STIME = default value (0xff = 4096 bit times) */
+		break;
+	case SK_LMODE_STAT_AUTOFULL:
+	case SK_LMODE_STAT_FULL:
+		/* Configuration Actions for Full Duplex Mode */
+		/*
+		 * The duplex mode is configured by the PHY,
+		 * therefore it seems to be that there is nothing
+		 * to do here.
+		 */
+		break;
+	case SK_LMODE_STAT_UNKNOWN:
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
+		break;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ *	This function initilaizes the Pause Mode which should
+ *	be used for this port.
+ *	It should be called after successfully finishing
+ *	the Autonegotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitPauseMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Word;
+	SK_U32		DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/* Disable Pause Frame Reception */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_IGN_PF);
+	}
+	else {
+		/*
+		 * enabling pause frame reception is required for 1000BT 
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Enable Pause Frame Reception */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~XM_MMU_IGN_PF);
+	}	
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/*
+		 * Configure Pause Frame Generation
+		 * Use internal and external Pause Frame Generation.
+		 * Sending pause frames is edge triggert. Send a
+		 * Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition
+		 * occurs. Send a zero pause time frame to
+		 * start transmission again.
+		 */
+
+		/* XM_PAUSE_DA = '010000C28001' (default) */
+
+		/* XM_MAC_PTIME = 0xffff (maximum) */
+		/* remember this value is defined in big endian (!) */
+		XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
+
+		/* Set Pause Mode in Mode Register */
+		XM_IN32(IoC, Port, XM_MODE, &DWord);
+		XM_OUT32(IoC, Port, XM_MODE, DWord | XM_PAUSE_MODE);
+
+		/* Set Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_ENA_PAUSE);
+	}
+	else {
+		/*
+		 * disable pause frame generation is required for 1000BT 
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Disable Pause Mode in Mode Register */
+		XM_IN32(IoC, Port, XM_MODE, &DWord);
+		XM_OUT32(IoC, Port, XM_MODE, DWord & ~XM_PAUSE_MODE);
+
+		/* Disable Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+
+}
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhy() - Initialize the XMAC II Phy registers
+ *
+ * Description:
+ *	Initialize all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitPhy(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_BCOM:
+		SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_LONE:
+		SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_NAT:
+		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+		break;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyXmac() - Initialize the XMAC II Phy registers
+ *
+ * Description:
+ *	Initialize all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyXmac: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyXmac: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+		Crtl = 0;
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl |= PHY_X_AN_HD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl |= PHY_X_AN_FD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl |= PHY_X_AN_FD | PHY_X_AN_HD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl |= PHY_X_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl |= PHY_X_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl |= PHY_X_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl |= PHY_X_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG) ;
+		}
+
+		/* Write AutoNeg Advertisement Register */
+		PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Crtl) ;
+
+		/* Restart Autonegotiation */
+		Crtl = PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Crtl) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description:
+ *	Initialize all the Broadcom Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl1 = PHY_B_CT_SP1000;
+	SK_U16		Crtl2 = 0;
+	SK_U16		Crtl3 = PHY_SEL_TYPE;
+	SK_U16		Crtl4 = PHY_B_PEC_EN_LTR;
+	SK_U16		Crtl5 = PHY_B_AC_TX_TST;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manuell Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Crtl2 |= PHY_B_1000C_MSE;
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Crtl2 |= PHY_B_1000C_MSC;
+		}
+	}
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyBcom: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manuell if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Crtl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyBcom: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl2 |= PHY_B_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl2 |= PHY_B_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl3 |= PHY_B_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl3 |= PHY_B_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl3 |= PHY_B_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl3 |= PHY_B_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Autonegotiation */
+		Crtl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+
+	}
+	
+	/* Initialize LED register here? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Crtl2);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("1000Base-T Control Reg = %x\n", Crtl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Crtl3);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+	
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* configure fifo to high latency for xmission of ext. packets*/
+		Crtl4 |= PHY_B_PEC_HIGH_LA;
+
+		/* configure reception of extended packets */
+		Crtl5 |= PHY_B_AC_LONG_PACK;
+
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Crtl5);
+	}
+
+	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Crtl4);
+	
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Crtl1);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("PHY Control Reg = %x\n", Crtl1));
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description:
+ *	Initialize all the Level One Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl1 = PHY_L_CT_SP1000;
+	SK_U16		Crtl2 = 0;
+	SK_U16		Crtl3 = PHY_SEL_TYPE;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manuell Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Crtl2 |= PHY_L_1000C_MSE;
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Crtl2 |= PHY_L_1000C_MSC;
+		}
+	}
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		/*
+		 * level one spec say: "1000Mbps: manual mode not allowed"
+		 * but lets see what happens...
+		 */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+			0, "Level One PHY only works with Autoneg");
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyLone: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manuell if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Crtl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyLone: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl2 |= PHY_L_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl2 |= PHY_L_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl3 |= PHY_L_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl3 |= PHY_L_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl3 |= PHY_L_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl3 |= PHY_L_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Autonegotiation */
+		Crtl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+
+	}
+	
+	/* Initialize LED register here ? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Crtl2);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("1000Base-T Control Reg = %x\n", Crtl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Crtl3);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+	
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/*
+		 * nothing to do for Level one.
+		 * PHY supports frames up to 10k.
+		 */
+	}
+	
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Crtl1);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("PHY Control Reg = %x\n", Crtl1));
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description:
+ *	Initialize all the National Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+/* todo: National */
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the Interrupt status word. If any of the
+ *	Autonegotiating interrupt bits are set, the PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(IStatus & (XM_IS_LIPA_RC|XM_IS_RX_PAGE|XM_IS_AND))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, IStatus));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaBcom() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaLone() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaNat() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+/******************************************************************************
+ *
+ *	SkXmAutoNegDone() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *	o This function is public because it is used in the diagnostics
+ *	  tool, too.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+int	SkXmAutoNegDone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		return (SkXmAutoNegDoneXmac(pAC, IoC, Port));
+	case SK_PHY_BCOM:
+		return (SkXmAutoNegDoneBcom(pAC, IoC, Port));
+	case SK_PHY_LONE:
+		return (SkXmAutoNegDoneLone(pAC, IoC, Port));
+	case SK_PHY_NAT:
+		return (SkXmAutoNegDoneNat(pAC, IoC, Port));
+	}
+	return(SK_AND_OTHER);
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneXmac() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneXmac"
+		"Port %d\n",Port));
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+	if (LPAb & PHY_X_AN_RFB) {
+		/* At least one of the remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	} else {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_DUP_CAP) ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
+	     pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
+	    (LPAb & PHY_X_P_SYM_MD)) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	} else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneBcom() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneBcom,"
+		" Port %d\n",Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+	if (LPAb & PHY_B_AN_RF) {
+		/* Remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000FD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else 	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	} else {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_DUP_CAP) ;
+	}
+	
+	/* Check Master/Slave resolution */
+	if (ResAb & (PHY_B_1000S_MSF)) {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return (SK_AND_OTHER);
+	} else if (ResAb & PHY_B_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
+	} else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == 
+		(PHY_B_AS_PRR | PHY_B_AS_PRT)) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	} else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneLone() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		QuickStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneLone"
+		"Port %d\n",Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_1000T_STAT, &ResAb);
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+	if (LPAb & PHY_L_AN_RF) {
+		/* Remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if (QuickStat & PHY_L_QS_DUP_MOD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	}
+	
+	/* Check Master/Slave resolution */
+	if (ResAb & (PHY_L_1000S_MSF)) {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT ;
+		return (SK_AND_OTHER);
+	} else if (ResAb & PHY_L_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
+	} else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	/* we must manually resolve the abilities here */
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	switch (pPrt->PFlowCtrlMode) {
+	case SK_FLOW_MODE_NONE:
+		/* default */
+		break;
+	case SK_FLOW_MODE_LOC_SEND:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			(PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
+			/* Disable PAUSE receive, enable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+		}
+		break;
+	case SK_FLOW_MODE_SYMMETRIC:
+		if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	case SK_FLOW_MODE_SYM_OR_REM:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			PHY_L_QS_AS_PAUSE) {
+			/* Enable PAUSE receive, disable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+		}
+		else if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+			SKERR_HWI_E016, SKERR_HWI_E016MSG);
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK);
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneNat() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *	o This function is public because it is used in the diagnostics
+ *	  tool, too.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+/* todo: National */
+	return(SK_AND_OK);
+}
+
+/******************************************************************************
+ *
+ *	SkXmRxTxEnable() - Enable RxTx activity if port is up
+ *
+ * Description:
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	0	o.k.
+ *	!= 0	Error happened
+ */
+int SkXmRxTxEnable(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Reg ;		/* 16bit register value */
+	SK_U16		IntMask;	/* XMac interrupt mask */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (!pPrt->PHWLinkUp) {
+		/* The Hardware link is NOT up */
+		return(0) ;
+	}
+
+	if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
+	     pPrt->PAutoNegFail) {
+		/* Autonegotiation is not done or failed */
+		return(0) ;
+	}
+
+	/* Set Dup Mode and Pause Mode */
+	SkXmInitDupMd (pAC, IoC, Port);
+	SkXmInitPauseMd (pAC, IoC, Port);
+
+	/*
+	 * Initialize the Interrupt Mask Register. Default IRQs are...
+	 *	- Link Asynchronous Event
+	 *	- Link Partner requests config
+	 *	- Auto Negotiation Done
+	 *	- Rx Counter Event Overflow
+	 *	- Tx Counter Event Overflow
+	 *	- Transmit FIFO Underrun
+	 */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		IntMask = XM_DEF_MSK;
+	}
+	else {
+		/* disable GP0 interrupt bit */
+		IntMask = XM_DEF_MSK | XM_IS_INP_ASS;
+	}
+	XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+
+	/* RX/TX enable */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+	if (pPrt->PhyType != SK_PHY_XMAC &&
+		(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || 
+		 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+		Reg |= XM_MMU_GMII_FD;
+	}
+	switch (pPrt->PhyType) {
+	case SK_PHY_BCOM:
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
+			PHY_B_DEF_MSK);
+		break;
+	case SK_PHY_LONE:
+		PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
+			PHY_L_DEF_MSK);
+		break;
+	case SK_PHY_NAT:
+		/* todo National:
+		PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
+			PHY_N_DEF_MSK); */
+		/* no interrupts possible from National ??? */
+		break;
+	}
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+				      
+	return (0);
+}
+
+#ifndef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmIrq() - Interrupt service routine
+ *
+ * Description:
+ *	Services an Interrupt of the XMAC II
+ *
+ * Note:
+ *	The XMACs interrupt source register is NOT read here.
+ *	With an external PHY, some interrupt bits are not meaningfull
+ *	any more:
+ *	- LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
+ *	- LinkPartnerReqConfig (bit #10)	XM_IS_LIPA_RC
+ *	- Page Received (bit #9)		XM_IS_RX_PAGE
+ *	- NextPageLoadedForXmt (bit #8)		XM_IS_TX_PAGE
+ *	- AutoNegDone (bit #7)			XM_IS_AND
+ *	Also probably not valid any more is the GP0 input bit:
+ *	- GPRegisterBit0set			XM_IS_INP_ASS
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt status read from the XMAC */
+{
+	SK_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		/* mask bits that are not used with ext. PHY */
+		IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
+			XM_IS_RX_PAGE | XM_IS_TX_PAGE |
+			XM_IS_AND | XM_IS_INP_ASS);
+	}
+	
+	/*
+	 * LinkPartner Autonegable ?
+	 */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("XmacIrq Port %d Isr %x\n", Port, IStatus));
+
+	if (!pPrt->PHWLinkUp) {
+		/* Spurious XMAC interrupt */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: spurious interrupt on port %d\n",
+			 Port));
+		return;
+	}
+
+	if (IStatus & XM_IS_LNK_AE) {
+		/* not used GP0 is used instead */
+	}
+
+	if (IStatus & XM_IS_TX_ABORT) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_FRC_INT) {
+		/* not used. use ASIC IRQ instead if needed */
+	}
+
+	if (IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) {
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Signal to RLMT */
+		Para.Para32[0] = (SK_U32) Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+	}
+
+	if (IStatus & XM_IS_RX_PAGE) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_TX_PAGE) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_AND) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("SkXmIrq: AND on link that is up port %d\n", Port));
+	}
+
+	if (IStatus & XM_IS_TSC_OV) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_RXC_OV) {
+		Para.Para32[0] = (SK_U32) Port;
+		Para.Para32[1] = (SK_U32) IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+	}
+
+	if (IStatus & XM_IS_TXC_OV) {
+		Para.Para32[0] = (SK_U32) Port;
+		Para.Para32[1] = (SK_U32) IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+	}
+
+	if (IStatus & XM_IS_RXF_OV) {
+		/* normal situation -> no effect */
+	}
+
+	if (IStatus & XM_IS_TXF_UR) {
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E020,
+			SKERR_SIRQ_E020MSG) ;
+	}
+
+	if (IStatus & XM_IS_TX_COMP) {
+		/* not served here */
+	}
+
+	if (IStatus & XM_IS_RX_COMP) {
+		/* not served here */
+	}
+
+}
+#endif /* !SK_DIAG */
+
+/* End of file */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)