patch-2.4.23 linux-2.4.23/drivers/net/sk98lin/skgesirq.c

Next file: linux-2.4.23/drivers/net/sk98lin/ski2c.c
Previous file: linux-2.4.23/drivers/net/sk98lin/skgepnmi.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/net/sk98lin/skgesirq.c linux-2.4.23/drivers/net/sk98lin/skgesirq.c
@@ -1,16 +1,17 @@
 /******************************************************************************
  *
  * Name:	skgesirq.c
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.81 $
- * Date:	$Date: 2002/12/05 10:49:51 $
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.91 $
+ * Date:	$Date: 2003/07/04 12:46:22 $
  * Purpose:	Special IRQ module
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -26,6 +27,60 @@
  * History:
  *
  *	$Log: skgesirq.c,v $
+ *	Revision 1.91  2003/07/04 12:46:22  rschmidt
+ *	Added debug messages in SkGePortCheckUpGmac().
+ *	Added error log message and new driver event SK_DRV_DOWNSHIFT_DET
+ *	for Downshift detection (Yukon-Copper).
+ *	Editorial changes.
+ *	
+ *	Revision 1.90  2003/05/28 15:35:45  rschmidt
+ *	Added parameter AutoNeg in all SkGePortCheckUp...() to save code.
+ *	Added setting for AutoNeg only once in SkGePortCheckUp().
+ *	Moved defines for return codes of SkGePortCheckUp() to header file.
+ *	Editorial changes.
+ *	
+ *	Revision 1.89  2003/05/13 17:32:20  mkarl
+ *	Removed links to RLMT and PNMI for SLIM driver (SK_SLIM).
+ *	Separated GENESIS and YUKON only code to reduce code size.
+ *	
+ *	Revision 1.88  2003/05/06 13:20:34  rschmidt
+ *	Changed workaround for Tx hang in half duplex only for Genesis.
+ *	Replaced SkPnmiGetVar() calls for Tx Octets Counter
+ *	with SkXmMacStatistic() in SkGeSirqIsr().
+ *	Added defines around GENESIS resp. YUKON branches to reduce
+ *	code size for PXE.
+ *	Editorial changes.
+ *	
+ *	Revision 1.87  2003/04/28 09:18:31  rschmidt
+ *	Added increment for GITimeStampCnt (high dword for
+ *	Time Stamp Timer counter), when overflow IRQ occurs.
+ *	Disabled HW Error IRQ on 32-bit Yukon if sensor IRQ occurs
+ *	by changing the common mask stored in GIValIrqMask.
+ *	Changed handling for HW Error IRQ in SkGeSirqIsr().
+ *	Added clearing of the software forced IRQ in SkGeSirqIsr().
+ *	Editorial changes.
+ *	
+ *	Revision 1.86  2003/04/09 13:03:24  rschmidt
+ *	Added workaround for configuration of GPHY's Auto-negotiation
+ *	advertisement register after link down event in SkPhyIsrGmac().
+ *	
+ *	Revision 1.85  2003/04/08 16:39:02  rschmidt
+ *	Changed handling for different PhyTypes for source code
+ *	portability to PXE, UNDI.
+ *	Editorial changes.
+ *	
+ *	Revision 1.84  2003/03/31 07:01:43  mkarl
+ *	Corrected Copyright.
+ *	Editorial changes.
+ *	
+ *	Revision 1.83  2003/02/05 15:10:59  rschmidt
+ *	Fixed setting of PLinkSpeedUsed in SkHWLinkUp() when
+ *	auto-negotiation is disabled.
+ *	Editorial changes.
+ *	
+ *	Revision 1.82  2003/01/29 13:34:33  rschmidt
+ *	Added some typecasts to avoid compiler warnings.
+ *	
  *	Revision 1.81  2002/12/05 10:49:51  rschmidt
  *	Fixed missing Link Down Event for fiber (Bug Id #10768)
  *	Added reading of cable length when link is up
@@ -132,7 +187,7 @@
  *	Added workaround for half duplex hangup.
  *	
  *	Revision 1.58  2000/09/28 13:06:04  gklug
- *	fix: BCOM may NOT be touched if XMAC is in RESET state
+ *	fix: BCom may NOT be touched if XMAC is in RESET state
  *	
  *	Revision 1.57  2000/09/08 12:38:39  cgoos
  *	Added forgotten variable declaration.
@@ -353,26 +408,35 @@
  *
  */
 
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
 static const char SysKonnectFileId[] =
-	"$Id: skgesirq.c,v 1.81 2002/12/05 10:49:51 rschmidt Exp $" ;
+	"@(#) $Id: skgesirq.c,v 1.91 2003/07/04 12:46:22 rschmidt Exp $ (C) Marvell.";
+#endif
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#ifndef SK_SLIM
 #include "h/skgepnmi.h"		/* PNMI Definitions */
 #include "h/skrlmt.h"		/* RLMT Definitions */
+#endif
 #include "h/skdrv2nd.h"		/* Adapter Control and Driver specific Def. */
 
 /* local function prototypes */
-static int	SkGePortCheckUpXmac(SK_AC*, SK_IOC, int);
-static int	SkGePortCheckUpBcom(SK_AC*, SK_IOC, int);
-static int	SkGePortCheckUpGmac(SK_AC*, SK_IOC, int);
+#ifdef GENESIS
+static int	SkGePortCheckUpXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkGePortCheckUpBcom(SK_AC*, SK_IOC, int, SK_BOOL);
 static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* GENESIS */
+#ifdef YUKON
+static int	SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL);
 static void	SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* YUKON */
 #ifdef OTHER_PHY
-static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int);
-static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int);
+static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int, SK_BOOL);
 static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
 #endif /* OTHER_PHY */
 
+#ifdef GENESIS
 /*
  * array of Rx counter from XMAC which are checked
  * in AutoSense mode to check whether a link is not able to auto-negotiate.
@@ -385,6 +449,7 @@
 	XM_RXF_1023B,
 	XM_RXF_MAX_SZ
 } ;
+#endif /* GENESIS */
 
 #ifdef __C2MAN__
 /*
@@ -397,20 +462,13 @@
 {}
 #endif
 
-/* Define return codes of SkGePortCheckUp and CheckShort */
-#define	SK_HW_PS_NONE		0	/* No action needed */
-#define	SK_HW_PS_RESTART	1	/* Restart needed */
-#define	SK_HW_PS_LINK		2	/* Link Up actions needed */
-
 /******************************************************************************
  *
  *	SkHWInitDefSense() - Default Autosensing mode initialization
  *
- * Description:
- *	This function sets the PLinkMode for HWInit
- *
- * Note:
+ * Description: sets the PLinkMode for HWInit
  *
+ * Returns: N/A
  */
 static void SkHWInitDefSense(
 SK_AC	*pAC,	/* adapter context */
@@ -438,17 +496,17 @@
 }	/* SkHWInitDefSense */
 
 
+#ifdef GENESIS
 /******************************************************************************
  *
- *	SkHWSenseGetNext() - GetNextAutosensing Mode
+ *	SkHWSenseGetNext() - Get Next Autosensing Mode
  *
- * Description:
- *	This function handles the AutoSensing
+ * Description: gets the appropriate next mode
  *
  * Note:
  *
  */
-SK_U8 SkHWSenseGetNext(
+static SK_U8 SkHWSenseGetNext(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
 int		Port)	/* Port Index (MAC_1 + n) */
@@ -459,18 +517,18 @@
 
 	pPrt->PAutoNegTimeOut = 0;
 
-	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
 		/* Leave all as configured */
 		return(pPrt->PLinkModeConf);
 	}
 
-	if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) {
+    if (pPrt->PLinkMode == (SK_U8)SK_LMODE_AUTOFULL) {
 		/* Return next mode AUTOBOTH */
-		return(SK_LMODE_AUTOBOTH);
+        return ((SK_U8)SK_LMODE_AUTOBOTH);
 	}
 
 	/* Return default autofull */
-	return(SK_LMODE_AUTOFULL);
+    return ((SK_U8)SK_LMODE_AUTOFULL);
 }	/* SkHWSenseGetNext */
 
 
@@ -478,13 +536,11 @@
  *
  *	SkHWSenseSetNext() - Autosensing Set next mode
  *
- * Description:
- *	This function sets the appropriate next mode.
- *
- * Note:
+ * Description:	sets the appropriate next mode
  *
+ * Returns: N/A
  */
-void SkHWSenseSetNext(
+static void SkHWSenseSetNext(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
@@ -496,7 +552,7 @@
 
 	pPrt->PAutoNegTimeOut = 0;
 
-	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
 		return;
 	}
 
@@ -508,17 +564,16 @@
 
 	return;
 }	/* SkHWSenseSetNext */
+#endif /* GENESIS */
 
 
 /******************************************************************************
  *
  *	SkHWLinkDown() - Link Down handling
  *
- * Description:
- *	This function handles the Hardware link down signal
- *
- * Note:
+ * Description: handles the hardware link down signal
  *
+ * Returns: N/A
  */
 void SkHWLinkDown(
 SK_AC	*pAC,		/* adapter context */
@@ -538,7 +593,7 @@
 	/* Init default sense mode */
 	SkHWInitDefSense(pAC, IoC, Port);
 
-	if (!pPrt->PHWLinkUp) {
+	if (pPrt->PHWLinkUp == SK_FALSE) {
 		return;
 	}
 
@@ -549,8 +604,8 @@
 	pPrt->PHWLinkUp = SK_FALSE;
 
 	/* Reset Port stati */
-	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
-	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+    pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
 	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED;
 
 	/* Re-init Phy especially when the AutoSense default is set now */
@@ -568,11 +623,9 @@
  *
  *	SkHWLinkUp() - Link Up handling
  *
- * Description:
- *	This function handles the Hardware link up signal
- *
- * Note:
+ * Description: handles the hardware link up signal
  *
+ * Returns: N/A
  */
 void SkHWLinkUp(
 SK_AC	*pAC,	/* adapter context */
@@ -590,39 +643,52 @@
 
 	pPrt->PHWLinkUp = SK_TRUE;
 	pPrt->PAutoNegFail = SK_FALSE;
-	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
 
-	if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
-	    pPrt->PLinkMode != SK_LMODE_AUTOFULL &&
-	    pPrt->PLinkMode != SK_LMODE_AUTOBOTH) {
+    if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) {
 		/* Link is up and no Auto-negotiation should be done */
 
-		/* Configure Port */
-		
-		/* link speed should be the configured one */
-		pPrt->PLinkSpeedUsed = pPrt->PLinkSpeed;
+		/* Link speed should be the configured one */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+			/* default is 1000 Mbps */
+		case SK_LSPEED_1000MBPS:
+			pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+			break;
+		case SK_LSPEED_100MBPS:
+			pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS;
+			break;
+		case SK_LSPEED_10MBPS:
+			pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS;
+			break;
+		}
 
 		/* Set Link Mode Status */
 		if (pPrt->PLinkMode == SK_LMODE_FULL) {
 			pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL;
 		}
 		else {
-			pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF;
+            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF;
 		}
 
 		/* No flow control without auto-negotiation */
-		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+        pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
 
 		/* enable Rx/Tx */
-		SkMacRxTxEnable(pAC, IoC, Port);
+        (void)SkMacRxTxEnable(pAC, IoC, Port);
 	}
 }	/* SkHWLinkUp */
 
 
 /******************************************************************************
  *
- * SkMacParity	- does everything to handle MAC parity errors correctly
+ *	SkMacParity() - MAC parity workaround
  *
+ * Description: handles MAC parity errors correctly
+ *
+ * Returns: N/A
  */
 static void SkMacParity(
 SK_AC	*pAC,	/* adapter context */
@@ -631,21 +697,29 @@
 {
 	SK_EVPARA	Para;
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	SK_U32		TxMax;		/* TxMax Counter */
+	SK_U32		TxMax;		/* Tx Max Size Counter */
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Clear IRQ Tx Parity Error */
+#ifdef GENESIS
 	if (pAC->GIni.GIGenesis) {
+
 		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
 	}
-	else {
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
 		/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
 		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
-			(SK_U8)((pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
+			(SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+			pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
 	}
-
+#endif /* YUKON */
+	
 	if (pPrt->PCheckPar) {
+
 		if (Port == MAC_1) {
 			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
 		}
@@ -654,6 +728,7 @@
 		}
 		Para.Para64 = Port;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
 		Para.Para32[0] = Port;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 
@@ -661,15 +736,21 @@
 	}
 
 	/* Check whether frames with a size of 1k were sent */
+#ifdef GENESIS
 	if (pAC->GIni.GIGenesis) {
 		/* Snap statistic counters */
 		(void)SkXmUpdateStats(pAC, IoC, Port);
 		
 		(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
 	}
-	else {
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+
 		(void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
 	}
+#endif /* YUKON */
 	
 	if (TxMax > 0) {
 		/* From now on check the parity */
@@ -680,11 +761,11 @@
 
 /******************************************************************************
  *
- *	Hardware Error service routine
+ *	SkGeHwErr() - Hardware Error service routine
  *
- * Description:
+ * Description: handles all HW Error interrupts
  *
- * Notes:
+ * Returns: N/A
  */
 static void SkGeHwErr(
 SK_AC	*pAC,		/* adapter context */
@@ -707,50 +788,62 @@
 		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_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
 		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
 		Para.Para64 = 0;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
 	}
 
+#ifdef GENESIS
 	if (pAC->GIni.GIGenesis) {
+
 		if ((HwStatus & IS_NO_STAT_M1) != 0) {
 			/* Ignore it */
 			/* This situation is also indicated in the descriptor */
 			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
 		}
-	
+
 		if ((HwStatus & IS_NO_STAT_M2) != 0) {
 			/* Ignore it */
 			/* This situation is also indicated in the descriptor */
 			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
 		}
-	
+
 		if ((HwStatus & IS_NO_TIST_M1) != 0) {
 			/* Ignore it */
 			/* This situation is also indicated in the descriptor */
 			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
 		}
-	
+
 		if ((HwStatus & IS_NO_TIST_M2) != 0) {
 			/* Ignore it */
 			/* This situation is also indicated in the descriptor */
 			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
 		}
 	}
-	else {	/* YUKON */
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
 		/* This is necessary only for Rx timing measurements */
 		if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+			/* increment Time Stamp Timer counter (high) */
+			pAC->GIni.GITimeStampCnt++;
+
 			/* Clear Time Stamp Timer IRQ */
 			SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
 		}
 
 		if ((HwStatus & IS_IRQ_SENSOR) != 0) {
-			/* Clear I2C IRQ */
-			SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+			/* no sensors on 32-bit Yukon */
+			if (pAC->GIni.GIYukon32Bit) {
+				/* disable HW Error IRQ */
+				pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+			}
 		}
 	}
+#endif /* YUKON */
 
 	if ((HwStatus & IS_RAM_RD_PAR) != 0) {
 		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
@@ -781,6 +874,7 @@
 		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
 		Para.Para64 = MAC_1;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
 		Para.Para32[0] = MAC_1;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
@@ -792,6 +886,7 @@
 		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
 		Para.Para64 = MAC_2;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
 		Para.Para32[0] = MAC_2;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
@@ -800,11 +895,11 @@
 
 /******************************************************************************
  *
- *	Interrupt service routine
+ *	SkGeSirqIsr() - Special Interrupt Service Routine
  *
- * Description:
+ * Description: handles all non data transfer specific interrupts (slow path)
  *
- * Notes:
+ * Returns: N/A
  */
 void SkGeSirqIsr(
 SK_AC	*pAC,		/* adapter context */
@@ -814,13 +909,10 @@
 	SK_EVPARA	Para;
 	SK_U32		RegVal32;	/* Read register value */
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	unsigned 	Len;
-	SK_U64		Octets;
 	SK_U16 		PhyInt;
-	SK_U16 		PhyIMsk;
 	int			i;
 
-	if ((Istatus & IS_HW_ERR) != 0) {
+	if (((Istatus & IS_HW_ERR) & pAC->GIni.GIValIrqMask) != 0) {
 		/* read the HW Error Interrupt source */
 		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
 		
@@ -866,32 +958,47 @@
 		/* May be a normal situation in a server with a slow network */
 		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
 
-		/*
-		 * workaround: if in half duplex mode, check for Tx hangup.
-		 * Read number of TX'ed bytes, wait for 10 ms, then compare
-		 * the number with current value. If nothing changed, we assume
-		 * that Tx is hanging and do a FIFO flush (see event routine).
-		 */
-		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
-		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
-		    !pPrt->HalfDupTimerActive) {
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
 			/*
-			 * many more pack. arb. timeouts may come in between,
-			 * we ignore those
+			 * workaround: if in half duplex mode, check for Tx hangup.
+			 * Read number of TX'ed bytes, wait for 10 ms, then compare
+			 * the number with current value. If nothing changed, we assume
+			 * that Tx is hanging and do a FIFO flush (see event routine).
 			 */
-			pPrt->HalfDupTimerActive = SK_TRUE;
+			if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+				!pPrt->HalfDupTimerActive) {
+				/*
+				 * many more pack. arb. timeouts may come in between,
+				 * we ignore those
+				 */
+				pPrt->HalfDupTimerActive = SK_TRUE;
+#ifdef XXX
+				Len = sizeof(SK_U64);
+				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
+					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 0),
+					pAC->Rlmt.Port[0].Net->NetNumber);
+				
+				pPrt->LastOctets = Octets;
+#endif /* XXX */
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, 0);
 
-			Len = sizeof(SK_U64);
-			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-				&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 0),
-				pAC->Rlmt.Port[0].Net->NetNumber);
-			
-			pPrt->LastOctets = Octets;
-			
-			Para.Para32[0] = 0;
-			SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
-				SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+				(void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_HI, &RegVal32);
+
+				pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_LO, &RegVal32);
+
+				pPrt->LastOctets += RegVal32;
+				
+				Para.Para32[0] = 0;
+				SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+					SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+			}
 		}
+#endif /* GENESIS */
 	}
 
 	if ((Istatus & IS_PA_TO_TX2) != 0) {
@@ -901,23 +1008,38 @@
 		/* May be a normal situation in a server with a slow network */
 		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
 
-		/* workaround: see above */
-		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
-		     pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
-		    !pPrt->HalfDupTimerActive) {
-			pPrt->HalfDupTimerActive = SK_TRUE;
-
-			Len = sizeof(SK_U64);
-			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-				&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 1),
-				pAC->Rlmt.Port[1].Net->NetNumber);
-			
-			pPrt->LastOctets = Octets;
-			
-			Para.Para32[0] = 1;
-			SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
-				SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			/* workaround: see above */
+			if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+				!pPrt->HalfDupTimerActive) {
+				pPrt->HalfDupTimerActive = SK_TRUE;
+#ifdef XXX
+				Len = sizeof(SK_U64);
+				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
+					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 1),
+					pAC->Rlmt.Port[1].Net->NetNumber);
+				
+				pPrt->LastOctets = Octets;
+#endif /* XXX */
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, 1);
+
+				(void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_HI, &RegVal32);
+
+				pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_LO, &RegVal32);
+
+				pPrt->LastOctets += RegVal32;
+				
+				Para.Para32[0] = 1;
+				SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+					SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+			}
 		}
+#endif /* GENESIS */
 	}
 
 	/* Check interrupts of the particular queues */
@@ -998,59 +1120,69 @@
 				continue;
 			}
 			
-			switch (pPrt->PhyType) {
-			
-			case SK_PHY_XMAC:
-				break;
-			
-			case SK_PHY_BCOM:
-				SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
-				SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_MASK, &PhyIMsk);
-
-				if ((PhyInt & ~PhyIMsk) != 0) {
-					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-						("Port %d Bcom Int: 0x%04X Mask: 0x%04X\n",
-						i, PhyInt, PhyIMsk));
-					SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+#ifdef GENESIS
+			if (pAC->GIni.GIGenesis) {
+				
+				switch (pPrt->PhyType) {
+				
+				case SK_PHY_XMAC:
+					break;
+				
+				case SK_PHY_BCOM:
+					SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
+	
+					if ((PhyInt & ~PHY_B_DEF_MSK) != 0) {
+						SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+							("Port %d Bcom Int: 0x%04X\n",
+							i, PhyInt));
+						SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+					}
+					break;
+#ifdef OTHER_PHY
+				case SK_PHY_LONE:
+					SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
+					
+					if ((PhyInt & PHY_L_DEF_MSK) != 0) {
+						SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+							("Port %d Lone Int: %x\n",
+							i, PhyInt));
+						SkPhyIsrLone(pAC, IoC, i, PhyInt);
+					}
+					break;
+#endif /* OTHER_PHY */
 				}
-				break;
-			
-			case SK_PHY_MARV_COPPER:
-			case SK_PHY_MARV_FIBER:
+			}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+			if (pAC->GIni.GIYukon) {
+				/* Read PHY Interrupt Status */
 				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
-				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_MASK, &PhyIMsk);
 
-				if ((PhyInt & PhyIMsk) != 0) {
+				if ((PhyInt & PHY_M_DEF_MSK) != 0) {
 					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-						("Port %d Marv Int: 0x%04X Mask: 0x%04X\n",
-						i, PhyInt, PhyIMsk));
+						("Port %d Marv Int: 0x%04X\n",
+						i, PhyInt));
 					SkPhyIsrGmac(pAC, IoC, i, PhyInt);
 				}
-				break;
-
-#ifdef OTHER_PHY
-			case SK_PHY_LONE:
-				SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
-				SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_ENAB, &PhyIMsk);
-				
-				if ((PhyInt & PhyIMsk) != 0) {
-					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-						("Port %d Lone Int: %x Mask: %x\n",
-						i, PhyInt, PhyIMsk));
-					SkPhyIsrLone(pAC, IoC, i, PhyInt);
-				}
-				break;
-			case SK_PHY_NAT:
-				/* todo: National */
-				break;
-#endif /* OTHER_PHY */
 			}
+#endif /* YUKON */
 		}
 	}
 
 	/* I2C Ready interrupt */
 	if ((Istatus & IS_I2C_READY) != 0) {
+#ifdef SK_SLIM
+        SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+#else		
 		SkI2cIsr(pAC, IoC);
+#endif		
+	}
+
+	/* SW forced interrupt */
+	if ((Istatus & IS_IRQ_SW) != 0) {
+		/* clear the software IRQ */
+		SK_OUT8(IoC, B0_CTST, CS_CL_SW_IRQ);
 	}
 
 	if ((Istatus & IS_LNK_SYNC_M1) != 0) {
@@ -1085,20 +1217,30 @@
 
 	/* Timer interrupt (served last) */
 	if ((Istatus & IS_TIMINT) != 0) {
+		/* check for HW Errors */
+		if (((Istatus & IS_HW_ERR) & ~pAC->GIni.GIValIrqMask) != 0) {
+			/* read the HW Error Interrupt source */
+			SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+			SkGeHwErr(pAC, IoC, RegVal32);
+		}
+
 		SkHwtIsr(pAC, IoC);
 	}
+
 }	/* SkGeSirqIsr */
 
 
+#ifdef GENESIS
 /******************************************************************************
  *
- * SkGePortCheckShorts - Implementing XMAC Workaround Errata # 2
+ * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
  *
  * return:
  *	0	o.k. nothing needed
  *	1	Restart needed on this port
  */
-static int	SkGePortCheckShorts(
+static int SkGePortCheckShorts(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
@@ -1123,13 +1265,15 @@
 	(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
 
 	/*
-	 * Read Rx counter (packets seen on the network and not necessarily
+	 * Read Rx counters (packets seen on the network and not necessarily
 	 * really received.
 	 */
 	RxCts = 0;
 
 	for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+		
 		(void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
+		
 		RxCts += (SK_U64)RxTmp;
 	}
 
@@ -1199,44 +1343,76 @@
 
 	return(Rtv);
 }	/* SkGePortCheckShorts */
+#endif /* GENESIS */
 
 
 /******************************************************************************
  *
- * SkGePortCheckUp - Implementation of the Workaround for Errata #2
+ * SkGePortCheckUp() - Check if the link is up
  *
  * return:
  *	0	o.k. nothing needed
  *	1	Restart needed on this port
  *	2	Link came up
  */
-static int	SkGePortCheckUp(
+static int SkGePortCheckUp(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
-	switch (pAC->GIni.GP[Port].PhyType) {
-	case SK_PHY_XMAC:
-		return(SkGePortCheckUpXmac(pAC, IoC, Port));
-	case SK_PHY_BCOM:
-		return(SkGePortCheckUpBcom(pAC, IoC, Port));
-	case SK_PHY_MARV_COPPER:
-	case SK_PHY_MARV_FIBER:
-		return(SkGePortCheckUpGmac(pAC, IoC, Port));
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+	int			Rtv;		/* Return value */
+
+	Rtv = SK_HW_PS_NONE;
+	
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	}
+	else {
+		AutoNeg = SK_TRUE;
+	}
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+
+		switch (pPrt->PhyType) {
+		
+		case SK_PHY_XMAC:
+			Rtv = SkGePortCheckUpXmac(pAC, IoC, Port, AutoNeg);
+			break;
+		case SK_PHY_BCOM:
+			Rtv = SkGePortCheckUpBcom(pAC, IoC, Port, AutoNeg);
+			break;
 #ifdef OTHER_PHY
-	case SK_PHY_LONE:
-		return(SkGePortCheckUpLone(pAC, IoC, Port));
-	case SK_PHY_NAT:
-		return(SkGePortCheckUpNat(pAC, IoC, Port));
+		case SK_PHY_LONE:
+			Rtv = SkGePortCheckUpLone(pAC, IoC, Port, AutoNeg);
+			break;
+		case SK_PHY_NAT:
+			Rtv = SkGePortCheckUpNat(pAC, IoC, Port, AutoNeg);
+			break;
 #endif /* OTHER_PHY */
+		}
 	}
-	return(SK_HW_PS_NONE);
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		Rtv = SkGePortCheckUpGmac(pAC, IoC, Port, AutoNeg);
+	}
+#endif /* YUKON */
+
+	return(Rtv);	
 }	/* SkGePortCheckUp */
 
 
+#ifdef GENESIS
 /******************************************************************************
  *
- * SkGePortCheckUpXmac - Implementing of the Workaround Errata # 2
+ * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
  *
  * return:
  *	0	o.k. nothing needed
@@ -1246,7 +1422,8 @@
 static int SkGePortCheckUpXmac(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int		Port)		/* Which port should be checked */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
 {
 	SK_U32		Shorts;		/* Short Event Counter */
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
@@ -1257,7 +1434,6 @@
 	SK_U16		LpAb;		/* Link Partner Ability */
 	SK_U16		ResAb;		/* Resolved Ability */
 	SK_U16		ExtStat;	/* Extended Status Register */
-	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
 	SK_U8		NextMode;	/* Next AutoSensing Mode */
 
 	pPrt = &pAC->GIni.GP[Port];
@@ -1275,13 +1451,6 @@
 	pPrt->PIsave = 0;
 
 	/* Now wait for each port's link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
-		AutoNeg = SK_FALSE;
-	}
-	else {
-		AutoNeg = SK_TRUE;
-	}
-
 	if (pPrt->PLinkBroken) {
 		/* Link was broken */
 		XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
@@ -1291,6 +1460,7 @@
 			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 			IsrcSum |= Isrc;
 			SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+			
 			if ((Isrc & XM_IS_INP_ASS) == 0) {
 				/* It has been in sync since last time */
 				/* Restart the PORT */
@@ -1329,7 +1499,7 @@
 					("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
 			}
 			else {
-				pPrt->PIsave = IsrcSum & XM_IS_AND;
+				pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
 				
 				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 					("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
@@ -1370,6 +1540,7 @@
 		}
 		else {
 			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+			
 			if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
 				return(SK_HW_PS_RESTART);
 			}
@@ -1389,7 +1560,7 @@
 	if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
 		if ((GpReg & XM_GP_INP_ASS) == 0) {
 			/* Save Auto-negotiation Done interrupt only if link is in sync */
-			pPrt->PIsave = IsrcSum & XM_IS_AND;
+			pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
 		}
 #ifdef DEBUG
 		if ((pPrt->PIsave & XM_IS_AND) != 0) {
@@ -1497,7 +1668,7 @@
 
 /******************************************************************************
  *
- * SkGePortCheckUpBcom - Check, if the link is up
+ * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
  *
  * return:
  *	0	o.k. nothing needed
@@ -1505,9 +1676,10 @@
  *	2	Link came up
  */
 static int SkGePortCheckUpBcom(
-SK_AC	*pAC,	/* Adapter Context */
-SK_IOC	IoC,	/* IO Context */
-int		Port)	/* Which port should be checked */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	int			Done;
@@ -1519,7 +1691,6 @@
 	SK_U16		LpAb;
 	SK_U16		ExtStat;
 #endif /* DEBUG */
-	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -1596,7 +1767,7 @@
 
 	if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
 		/*
-		 * Workaround BCOM Errata:
+		 * Workaround BCom Errata:
 		 *	enable and disable loopback mode if "NO HCD" occurs.
 		 */
 		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
@@ -1689,14 +1860,6 @@
 	}
 #endif /* DEBUG */
 
-	/* Now wait for each port's link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
-		AutoNeg = SK_FALSE;
-	}
-	else {
-		AutoNeg = SK_TRUE;
-	}
-
 	/*
 	 * Here we usually can check whether the link is in sync and
 	 * auto-negotiation is done.
@@ -1707,7 +1870,7 @@
 	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
 	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
+		("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat));
 
 	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
 
@@ -1715,6 +1878,7 @@
 		/* 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;
 		
@@ -1729,7 +1893,7 @@
 		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
 	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
+		("Port %d, ResAb: 0x%04X\n", Port, ResAb));
 
 	if (AutoNeg) {
 		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
@@ -1793,16 +1957,19 @@
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 			("Link sync(GP), Port %d\n", Port));
 		SkHWLinkUp(pAC, IoC, Port);
+		
 		return(SK_HW_PS_LINK);
 	}
 
 	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUpBcom */
+#endif /* GENESIS */
 
 
+#ifdef YUKON
 /******************************************************************************
  *
- * SkGePortCheckUpGmac - Check, if the link is up
+ * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
  *
  * return:
  *	0	o.k. nothing needed
@@ -1810,44 +1977,43 @@
  *	2	Link came up
  */
 static int SkGePortCheckUpGmac(
-SK_AC	*pAC,	/* Adapter Context */
-SK_IOC	IoC,	/* IO Context */
-int		Port)	/* Which port should be checked */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	int			Done;
-	SK_U16		Isrc;		/* Interrupt source */
-	SK_U16		PhyStat;	/* Phy Status */
-	SK_U16		PhySpecStat;/* Phy Specific Status */
+	SK_U16		PhyIsrc;	/* PHY Interrupt source */
+	SK_U16		PhyStat;	/* PPY Status */
+	SK_U16		PhySpecStat;/* PHY Specific Status */
 	SK_U16		ResAb;		/* Master/Slave resolution */
-	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+	SK_EVPARA	Para;
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Read PHY Interrupt Status */
-	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &Isrc);
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc);
 
-	if ((Isrc & PHY_M_IS_AN_COMPL) != 0) {
-		/* TBD */
+	if ((PhyIsrc & PHY_M_IS_AN_COMPL) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Auto-Negotiation Completed, PhyIsrc: 0x%04X\n", PhyIsrc));
 	}
 
-	if (pPrt->PHWLinkUp) {
-		return(SK_HW_PS_NONE);
+	if ((PhyIsrc & PHY_M_IS_LSP_CHANGE) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc));
 	}
 
-	/* Now wait for each port's link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
-		AutoNeg = SK_FALSE;
-	}
-	else {
-		AutoNeg = SK_TRUE;
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
 	}
 
 	/* Read PHY Status */
 	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
 
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
+		("AutoNeg: %d, PhyStat: 0x%04X\n", AutoNeg, PhyStat));
 
 	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
 	
@@ -1857,6 +2023,7 @@
 		/* 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;
 		
@@ -1867,12 +2034,24 @@
 	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
 	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg: %d, PhySpecStat: 0x%04x\n", AutoNeg, PhySpecStat));
+		("AutoNeg: %d, PhySpecStat: 0x%04X\n", AutoNeg, PhySpecStat));
 
 	if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
 		return(SK_HW_PS_NONE);
 	}
 	
+	if ((PhySpecStat & PHY_M_PS_DOWNS_STAT) != 0 ||
+		(PhyIsrc & PHY_M_IS_DOWNSH_DET) != 0) {
+		/* Downshift detected */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E025, SKERR_SIRQ_E025MSG);
+		
+		Para.Para64 = Port;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_DOWNSHIFT_DET, Para);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Downshift detected, PhyIsrc: 0x%04X\n", PhyIsrc));
+	}
+
 	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
 		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
 	
@@ -1913,12 +2092,13 @@
 
 	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUpGmac */
+#endif /* YUKON */
 
 
 #ifdef OTHER_PHY
 /******************************************************************************
  *
- * SkGePortCheckUpLone - Check if the link is up
+ * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
  *
  * return:
  *	0	o.k. nothing needed
@@ -1928,7 +2108,8 @@
 static int SkGePortCheckUpLone(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int		Port)		/* Which port should be checked */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	int			Done;
@@ -1937,7 +2118,6 @@
 	SK_U16		ExtStat;	/* Extended Status Register */
 	SK_U16		PhyStat;	/* Phy Status Register */
 	SK_U16		StatSum;
-	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
 	SK_U8		NextMode;	/* Next AutoSensing Mode */
 
 	pPrt = &pAC->GIni.GP[Port];
@@ -1949,14 +2129,6 @@
 	StatSum = pPrt->PIsave;
 	pPrt->PIsave = 0;
 
-	/* Now wait for each ports link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
-		AutoNeg = SK_FALSE;
-	}
-	else {
-		AutoNeg = SK_TRUE;
-	}
-
 	/*
 	 * here we usually can check whether the link is in sync and
 	 * auto-negotiation is done.
@@ -2049,6 +2221,7 @@
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 			("Link sync(GP), Port %d\n", Port));
 		SkHWLinkUp(pAC, IoC, Port);
+		
 		return(SK_HW_PS_LINK);
 	}
 
@@ -2058,7 +2231,7 @@
 
 /******************************************************************************
  *
- * SkGePortCheckUpNat - Check if the link is up
+ * SkGePortCheckUpNat() - Check if the link is up on National PHY
  *
  * return:
  *	0	o.k. nothing needed
@@ -2068,7 +2241,8 @@
 static int SkGePortCheckUpNat(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int		Port)		/* Which port should be checked */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
 {
 	/* todo: National */
 	return(SK_HW_PS_NONE);
@@ -2078,7 +2252,7 @@
 
 /******************************************************************************
  *
- *	Event service routine
+ *	SkGeSirqEvent() - Event Service Routine
  *
  * Description:
  *
@@ -2090,13 +2264,14 @@
 SK_U32		Event,		/* Module specific Event */
 SK_EVPARA	Para)		/* Event specific Parameter */
 {
-	SK_U64		Octets;
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	SK_U32		Port;
-	SK_U32		Time;
-	unsigned	Len;
+	SK_U32		Val32;
 	int			PortStat;
 	SK_U8		Val8;
+#ifdef GENESIS
+	SK_U64		Octets;
+#endif /* GENESIS */
 
 	Port = Para.Para32[0];
 	pPrt = &pAC->GIni.GP[Port];
@@ -2104,15 +2279,13 @@
 	switch (Event) {
 	case SK_HWEV_WATIM:
 		/* Check whether port came up */
-		PortStat = SkGePortCheckUp(pAC, IoC, Port);
+		PortStat = SkGePortCheckUp(pAC, IoC, (int)Port);
 
 		switch (PortStat) {
 		case SK_HW_PS_RESTART:
 			if (pPrt->PHWLinkUp) {
-				/*
-				 * Set Link to down.
-				 */
-				SkHWLinkDown(pAC, IoC, Port);
+				/* Set Link to down */
+				SkHWLinkDown(pAC, IoC, (int)Port);
 
 				/*
 				 * Signal directly to RLMT to ensure correct
@@ -2129,20 +2302,19 @@
 			/* Signal to RLMT */
 			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
 			break;
-
 		}
 		
 		/* Start again the check Timer */
 		if (pPrt->PHWLinkUp) {
-			Time = SK_WA_ACT_TIME;
+			Val32 = SK_WA_ACT_TIME;
 		}
 		else {
-			Time = SK_WA_INA_TIME;
+			Val32 = SK_WA_INA_TIME;
 		}
 
 		/* Todo: still needed for non-XMAC PHYs??? */
 		/* Start workaround Errata #2 timer */
-		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Time,
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Val32,
 			SKGE_HWAC, SK_HWEV_WATIM, Para);
 		break;
 
@@ -2155,7 +2327,7 @@
 			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
 		}
 
-		SkHWLinkDown(pAC, IoC, Port);
+		SkHWLinkDown(pAC, IoC, (int)Port);
 
 		/* Schedule Port RESET */
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
@@ -2177,7 +2349,7 @@
 		/* Stop Workaround Timer */
 		SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
 
-		SkHWLinkDown(pAC, IoC, Port);
+		SkHWLinkDown(pAC, IoC, (int)Port);
 		break;
 
 	case SK_HWEV_UPDATE_STAT:
@@ -2224,7 +2396,7 @@
 		}
 		Val8 = (SK_U8)Para.Para32[1];
 		if (pPrt->PMSMode != Val8) {
-			/* Set New link mode */
+			/* Set New Role (Master/Slave) mode */
 			pPrt->PMSMode = Val8;
 
 			/* Restart Port */
@@ -2248,26 +2420,41 @@
 		}
 		break;
 
+#ifdef GENESIS
 	case SK_HWEV_HALFDUP_CHK:
-		/*
-		 * half duplex hangup workaround.
-		 * See packet arbiter timeout interrupt for description
-		 */
-		pPrt->HalfDupTimerActive = SK_FALSE;
-		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
-		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
-			
-			Len = sizeof(SK_U64);
-			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-				&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
-				pAC->Rlmt.Port[Port].Net->NetNumber);
-			
-			if (pPrt->LastOctets == Octets) {
-				/* Tx hanging, a FIFO flush restarts it */
-				SkMacFlushTxFifo(pAC, IoC, Port);
+		if (pAC->GIni.GIGenesis) {
+			/*
+			 * half duplex hangup workaround.
+			 * See packet arbiter timeout interrupt for description
+			 */
+			pPrt->HalfDupTimerActive = SK_FALSE;
+			if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
+#ifdef XXX
+				Len = sizeof(SK_U64);
+				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
+					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+					pAC->Rlmt.Port[Port].Net->NetNumber);
+#endif /* XXX */
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, Port);
+
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_HI, &Val32);
+
+				Octets = (SK_U64)Val32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_LO, &Val32);
+
+				Octets += Val32;
+				
+				if (pPrt->LastOctets == Octets) {
+					/* Tx hanging, a FIFO flush restarts it */
+					SkMacFlushTxFifo(pAC, IoC, Port);
+				}
 			}
 		}
 		break;
+#endif /* GENESIS */
 	
 	default:
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
@@ -2278,11 +2465,12 @@
 }	/* SkGeSirqEvent */
 
 
+#ifdef GENESIS
 /******************************************************************************
  *
- *	SkPhyIsrBcom - PHY interrupt service routine
+ *	SkPhyIsrBcom() - PHY interrupt service routine
  *
- * Description: handle all interrupts from BCOM PHY
+ * Description: handles all interrupts from BCom PHY
  *
  * Returns: N/A
  */
@@ -2299,15 +2487,15 @@
 
 	if ((IStatus & PHY_B_IS_PSE) != 0) {
 		/* Incorrectable pair swap error */
-		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
 			SKERR_SIRQ_E022MSG);
 	}
 	
 	if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
-		Para.Para32[0] = (SK_U32)Port;
 
 		SkHWLinkDown(pAC, IoC, Port);
 
+		Para.Para32[0] = (SK_U32)Port;
 		/* Signal to RLMT */
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 
@@ -2317,13 +2505,15 @@
 	}
 
 }	/* SkPhyIsrBcom */
+#endif /* GENESIS */
 
 
+#ifdef YUKON
 /******************************************************************************
  *
- *	SkPhyIsrGmac - PHY interrupt service routine
+ *	SkPhyIsrGmac() - PHY interrupt service routine
  *
- * Description: handle all interrupts from Marvell PHY
+ * Description: handles all interrupts from Marvell PHY
  *
  * Returns: N/A
  */
@@ -2335,14 +2525,27 @@
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	SK_EVPARA	Para;
+	SK_U16		Word;
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
-		Para.Para32[0] = (SK_U32)Port;
 
 		SkHWLinkDown(pAC, IoC, Port);
 
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &Word);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNeg.Adv: 0x%04X\n", Word));
+		
+		/* Set Auto-negotiation advertisement */
+		if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) {
+			/* restore Asymmetric Pause bit */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV,
+				(SK_U16)(Word | PHY_M_AN_ASP));
+		}
+		
+		Para.Para32[0] = (SK_U32)Port;
 		/* Signal to RLMT */
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
@@ -2352,23 +2555,21 @@
 		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
 	}
 	
-	if ((IStatus & PHY_M_IS_LSP_CHANGE) != 0) {
-		/* TBD */
-	}
-	
 	if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
 		/* FIFO Overflow/Underrun Error */
 		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
 	}
+	
 }	/* SkPhyIsrGmac */
+#endif /* YUKON */
 
 
 #ifdef OTHER_PHY
 /******************************************************************************
  *
- *	SkPhyIsrLone - PHY interrupt service routine
+ *	SkPhyIsrLone() - PHY interrupt service routine
  *
- * Description: handle all interrupts from LONE PHY
+ * Description: handles all interrupts from LONE PHY
  *
  * Returns: N/A
  */
@@ -2381,10 +2582,11 @@
 	SK_EVPARA	Para;
 
 	if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
+		
 		SkHWLinkDown(pAC, IoC, Port);
 
-		/* Signal to RLMT */
 		Para.Para32[0] = (SK_U32)Port;
+		/* Signal to RLMT */
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 

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