drivers/net : move net drivers to drivers/net

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
diff --git a/drivers/net/3c589.c b/drivers/net/3c589.c
new file mode 100644
index 0000000..080b686
--- /dev/null
+++ b/drivers/net/3c589.c
@@ -0,0 +1,519 @@
+/*------------------------------------------------------------------------
+ . 3c589.c
+ . This is a driver for 3Com's 3C589 (Etherlink III) PCMCIA Ethernet device.
+ .
+ . (C) Copyright 2002
+ . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ . Rolf Offermanns <rof@sysgo.de>
+ .
+ . 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.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ ----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_3C589
+
+#include "3c589.h"
+
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN	0
+
+#define NO_AUTOPROBE
+
+static const char version[] =
+	"Your ad here! :P\n";
+
+
+#undef EL_DEBUG
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long int dword;
+/*------------------------------------------------------------------------
+ .
+ . Configuration options, for the experienced user to change.
+ .
+ -------------------------------------------------------------------------*/
+
+/*
+ . Wait time for memory to be free.  This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+
+#if (EL_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if EL_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef EL_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+#define outb(args...)	mmio_outb(args)
+#define mmio_outb(value, addr)	(*((volatile byte *)(addr)) = value)
+
+#define inb(args...)	mmio_inb(args)
+#define mmio_inb(addr) (*((volatile byte *)(addr)))
+
+#define outw(args...)	mmio_outw(args)
+#define mmio_outw(value, addr)	(*((volatile word *)(addr)) = value)
+
+#define inw(args...)	mmio_inw(args)
+#define mmio_inw(addr) (*((volatile word *)(addr)))
+
+#define outsw(args...)	mmio_outsw(args)
+#define mmio_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    mmio_outw( *(__b2 + __i), r); \
+					} \
+				})
+
+#define insw(args...)	mmio_insw(args)
+#define mmio_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+					__b2 = (word *) b;  \
+					for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = mmio_inw(r);  \
+					  mmio_inw(0);  \
+					};  \
+				})
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver.  If you are changing anything
+ . here with the 3Com stuff, you should have the datasheet and know
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+#define EL_BASE_ADDR	0x20000000
+
+
+/* Offsets from base I/O address. */
+#define EL3_DATA	0x00
+#define EL3_TIMER	0x0a
+#define EL3_CMD		0x0e
+#define EL3_STATUS	0x0e
+
+#define EEPROM_READ	0x0080
+
+#define EL3WINDOW(win_num) mmio_outw(SelectWindow + (win_num), EL_BASE_ADDR + EL3_CMD)
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable. */
+enum c509cmd {
+    TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+    RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
+    TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+    FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+    SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+    SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
+    StatsDisable = 22<<11, StopCoax = 23<<11,
+};
+
+enum c509status {
+    IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+    TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+    IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000
+};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+    RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+/* Register window 1 offsets, the window used in normal operation. */
+#define TX_FIFO		0x00
+#define RX_FIFO		0x00
+#define RX_STATUS 	0x08
+#define TX_STATUS 	0x0B
+#define TX_FREE		0x0C	/* Remaining free bytes in Tx buffer. */
+
+
+/*
+  Read a word from the EEPROM using the regular EEPROM access register.
+  Assume that we are in register window zero.
+*/
+static word read_eeprom(dword ioaddr, int index)
+{
+    int i;
+    outw(EEPROM_READ + index, ioaddr + 0xa);
+    /* Reading the eeprom takes 162 us */
+    for (i = 1620; i >= 0; i--)
+	if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
+	    break;
+    return inw(ioaddr + 0xc);
+}
+
+static void el_get_mac_addr( unsigned char *mac_addr )
+{
+	int i;
+	union
+	{
+		word w;
+		unsigned char b[2];
+	} wrd;
+	unsigned char old_window = inw( EL_BASE_ADDR + EL3_STATUS ) >> 13;
+	GO_WINDOW(0);
+	VX_BUSY_WAIT;
+	for (i = 0; i < 3; i++)
+	{
+		wrd.w = read_eeprom(EL_BASE_ADDR, 0xa+i);
+#ifdef __BIG_ENDIAN
+		mac_addr[2*i]   = wrd.b[0];
+		mac_addr[2*i+1] = wrd.b[1];
+#else
+		mac_addr[2*i]   = wrd.b[1];
+		mac_addr[2*i+1] = wrd.b[0];
+#endif
+	}
+	GO_WINDOW(old_window);
+	VX_BUSY_WAIT;
+}
+
+
+#if EL_DEBUG > 1
+static void print_packet( byte * buf, int length )
+{
+	int i;
+	int remainder;
+	int lines;
+
+	PRINTK2("Packet of length %d \n", length );
+
+	lines = length / 16;
+	remainder = length % 16;
+
+	for ( i = 0; i < lines ; i ++ ) {
+		int cur;
+
+		for ( cur = 0; cur < 8; cur ++ ) {
+			byte a, b;
+
+			a = *(buf ++ );
+			b = *(buf ++ );
+			PRINTK2("%02x%02x ", a, b );
+		}
+		PRINTK2("\n");
+	}
+	for ( i = 0; i < remainder/2 ; i++ ) {
+		byte a, b;
+
+		a = *(buf ++ );
+		b = *(buf ++ );
+		PRINTK2("%02x%02x ", a, b );
+	}
+	PRINTK2("\n");
+}
+#endif /* EL_DEBUG > 1 */
+
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+***************************************************************************/
+static void el_reset(bd_t *bd)
+{
+	/***********************************************************
+			Reset 3Com 595 card
+	*************************************************************/
+	/* QUICK HACK
+	 * - adjust timing for 3c589
+	 * - enable io for PCMCIA */
+	outw(0x0004, 0xa0000018);
+	udelay(100);
+	outw(0x0041, 0x28010000);
+	udelay(100);
+
+	/* issue global reset */
+	outw(GLOBAL_RESET, BASE + VX_COMMAND);
+
+	/* must wait for at least 1ms */
+	udelay(100000000);
+
+	/* set mac addr */
+	{
+		unsigned char *mac_addr = bd->bi_enetaddr;
+		int i;
+
+		el_get_mac_addr( mac_addr );
+
+		GO_WINDOW(2);
+		VX_BUSY_WAIT;
+
+		printf("3C589 MAC Addr.: ");
+		for (i = 0; i < 6; i++)
+		{
+			printf("%02x", mac_addr[i]);
+			outb(mac_addr[i], BASE + VX_W2_ADDR_0 + i);
+			VX_BUSY_WAIT;
+		}
+		printf("\n\n");
+	}
+
+	/* set RX filter */
+	outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+
+	/* set irq mask and read_zero */
+	outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+	outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+	/* enable TP Linkbeat */
+	GO_WINDOW(4);
+	VX_BUSY_WAIT;
+
+	outw( ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
+	VX_BUSY_WAIT;
+
+
+/*
+ * Attempt to get rid of any stray interrupts that occured during
+ * configuration.  On the i386 this isn't possible because one may
+ * already be queued.  However, a single stray interrupt is
+ * unimportant.
+ */
+
+	outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+	/* enable TX and RX */
+	outw( RX_ENABLE, BASE + VX_COMMAND );
+	VX_BUSY_WAIT;
+
+	outw( TX_ENABLE, BASE + VX_COMMAND );
+	VX_BUSY_WAIT;
+
+
+	/* print the diag. regs. */
+	PRINTK2("Diag. Regs\n");
+	PRINTK2("--> MEDIA_TYPE:   %04x\n", inw(BASE + VX_W4_MEDIA_TYPE));
+	PRINTK2("--> NET_DIAG:     %04x\n", inw(BASE + VX_W4_NET_DIAG));
+	PRINTK2("--> FIFO_DIAG:    %04x\n", inw(BASE + VX_W4_FIFO_DIAG));
+	PRINTK2("--> CTRLR_STATUS: %04x\n", inw(BASE + VX_W4_CTRLR_STATUS));
+	PRINTK2("\n\n");
+
+	/* enter working mode */
+	GO_WINDOW(1);
+	VX_BUSY_WAIT;
+
+	/* wait for another 1ms */
+	udelay(100000000);
+}
+
+
+/*-----------------------------------------------------------------
+ .
+ .  The driver can be entered at any of the following entry points.
+ .
+ .------------------------------------------------------------------  */
+
+extern int eth_init(bd_t *bd);
+extern void eth_halt(void);
+extern int eth_rx(void);
+extern int eth_send(volatile void *packet, int length);
+
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+int eth_init(bd_t *bd)
+{
+	el_reset(bd);
+	return 0;
+}
+
+void eth_halt() {
+	return;
+}
+
+#define EDEBUG 1
+
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+***************************************************************************/
+
+int eth_rx()
+{
+	word status, rx_status, packet_size;
+
+	VX_BUSY_WAIT;
+
+	status = inw( BASE + VX_STATUS );
+
+	if ( (status & S_RX_COMPLETE) == 0 ) return 0; /* nothing to do */
+
+	/* Packet waiting -> check RX_STATUS */
+	rx_status = inw( BASE + VX_W1_RX_STATUS );
+
+	if ( rx_status & ERR_RX )
+	{
+		/* error in packet -> discard */
+		PRINTK("[ERROR] Invalid packet -> discarding\n");
+		PRINTK("-- error code 0x%02x\n", rx_status & ERR_MASK);
+		PRINTK("-- rx bytes 0x%04d\n", rx_status & ((1<<11) - 1));
+		PRINTK("[ERROR] Invalid packet -> discarding\n");
+		outw( RX_DISCARD_TOP_PACK, BASE + VX_COMMAND );
+		return 0;
+	}
+
+	/* correct pack. waiting in fifo */
+	packet_size = rx_status & RX_BYTES_MASK;
+
+	PRINTK("Correct packet waiting in fifo, size: %d\n", packet_size);
+
+	{
+		volatile word *packet_start = (word *)(BASE + VX_W1_RX_PIO_RD_1);
+		word *RcvBuffer = (word *)(NetRxPackets[0]);
+		int wcount = 0;
+
+		for (wcount = 0; wcount < (packet_size >> 1); wcount++)
+		{
+			*RcvBuffer++ = *(packet_start);
+		}
+
+		/* handle odd packets */
+		if ( packet_size & 1 )
+		{
+			*RcvBuffer++ = *(packet_start);
+		}
+	}
+
+	/* fifo should now be empty (besides the padding bytes) */
+	if ( ((*((word *)(BASE + VX_W1_RX_STATUS))) & RX_BYTES_MASK) > 3 )
+	{
+		PRINTK("[ERROR] Fifo not empty after packet read (remaining pkts: %d)\n",
+			(((*(word *)(BASE + VX_W1_RX_STATUS))) & RX_BYTES_MASK));
+	}
+
+	/* discard packet */
+	*((word *)(BASE + VX_COMMAND)) = RX_DISCARD_TOP_PACK;
+
+	/* Pass Packets to upper Layer */
+	NetReceive(NetRxPackets[0], packet_size);
+	return packet_size;
+}
+
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+***************************************************************************/
+static char padmap[] = {
+	0, 3, 2, 1};
+
+
+int eth_send(volatile void *packet, int length) {
+	int pad;
+	int status;
+	volatile word *buf = (word *)packet;
+	int dummy = 0;
+
+	/* padding stuff */
+	pad = padmap[length & 3];
+
+	PRINTK("eth_send(), length: %d\n", length);
+	/* drop acknowledgements */
+	while(( status=inb(EL_BASE_ADDR + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
+		if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
+			outw(TX_RESET, EL_BASE_ADDR + VX_COMMAND);
+			outw(TX_ENABLE, EL_BASE_ADDR + VX_COMMAND);
+			PRINTK("Bad status, resetting and reenabling transmitter\n");
+		}
+
+		outb(0x0, EL_BASE_ADDR + VX_W1_TX_STATUS);
+	}
+
+
+	while (inw(EL_BASE_ADDR + VX_W1_FREE_TX) < length + pad + 4) {
+		/* no room in FIFO */
+		if (dummy == 0)
+		{
+			PRINTK("No room in FIFO, waiting...\n");
+			dummy++;
+		}
+
+	}
+
+	PRINTK("    ---> FIFO ready\n");
+
+
+	outw(length, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
+
+	/* Second dword meaningless */
+	outw(0x0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
+
+#if EL_DEBUG > 1
+	print_packet((byte *)buf, length);
+#endif
+
+	/* write packet */
+	{
+		unsigned int i, totw;
+
+		totw = ((length + 1) >> 1);
+		PRINTK("Buffer: (totw = %d)\n", totw);
+		for (i = 0; i < totw; i++) {
+			outw( *(buf+i), EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
+			udelay(10);
+		}
+		if(totw & 1)
+		{	/* pad to double word length */
+			outw( 0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
+			udelay(10);
+		}
+		PRINTK("\n\n");
+	}
+
+	/* wait for Tx complete */
+	PRINTK("Waiting for Tx to complete...\n");
+	while(((status = inw(EL_BASE_ADDR + VX_STATUS)) & S_COMMAND_IN_PROGRESS) != 0)
+	{
+		udelay(10);
+	}
+	PRINTK("   ---> Tx completed, status = 0x%04x\n", status);
+
+	return length;
+}
+
+
+#endif /* CONFIG_DRIVER_3C589 */
diff --git a/drivers/net/3c589.h b/drivers/net/3c589.h
new file mode 100644
index 0000000..6735bf9
--- /dev/null
+++ b/drivers/net/3c589.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2. The name
+ * of the author may not be used to endorse or promote products derived from
+ * this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ October 2, 1994
+
+ Modified by: Andres Vega Garcia
+
+ INRIA - Sophia Antipolis, France
+ e-mail: avega@sophia.inria.fr
+ finger: avega@pax.inria.fr
+
+ */
+
+/*
+ * Created from if_epreg.h by Fred Gray (fgray@rice.edu) to support the
+ * 3c590 family.
+ */
+
+/*
+ * Modified by Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
+ * for etherboot
+ * Mar. 14, 2000
+*/
+
+/*
+ * Ethernet software status per interface.
+ */
+
+/*
+ * Some global constants
+ */
+
+#define TX_INIT_RATE         16
+#define TX_INIT_MAX_RATE     64
+#define RX_INIT_LATENCY      64
+#define RX_INIT_EARLY_THRESH 64
+#define MIN_RX_EARLY_THRESHF   16 /* not less than ether_header */
+#define MIN_RX_EARLY_THRESHL   4
+
+#define EEPROMSIZE      0x40
+#define MAX_EEPROMBUSY  1000
+#define VX_LAST_TAG     0xd7
+#define VX_MAX_BOARDS   16
+#define VX_ID_PORT      0x100
+
+/*
+ * some macros to acces long named fields
+ */
+#define BASE 	(EL_BASE_ADDR)
+
+/*
+ * Commands to read/write EEPROM trough EEPROM command register (Window 0,
+ * Offset 0xa)
+ */
+#define EEPROM_CMD_RD    0x0080	/* Read:  Address required (5 bits) */
+#define EEPROM_CMD_WR    0x0040	/* Write: Address required (5 bits) */
+#define EEPROM_CMD_ERASE 0x00c0	/* Erase: Address required (5 bits) */
+#define EEPROM_CMD_EWEN  0x0030	/* Erase/Write Enable: No data required */
+
+#define EEPROM_BUSY		(1<<15)
+
+/*
+ * Some short functions, worth to let them be a macro
+ */
+
+/**************************************************************************
+ *									  *
+ * These define the EEPROM data structure.  They are used in the probe
+ * function to verify the existence of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0	0x0	/* Word */
+#define EEPROM_NODE_ADDR_1	0x1	/* Word */
+#define EEPROM_NODE_ADDR_2	0x2	/* Word */
+#define EEPROM_PROD_ID		0x3	/* 0x9[0-f]50 */
+#define EEPROM_MFG_ID		0x7	/* 0x6d50 */
+#define EEPROM_ADDR_CFG		0x8	/* Base addr */
+#define EEPROM_RESOURCE_CFG	0x9	/* IRQ. Bits 12-15 */
+#define EEPROM_OEM_ADDR_0	0xa	/* Word */
+#define EEPROM_OEM_ADDR_1	0xb	/* Word */
+#define EEPROM_OEM_ADDR_2	0xc	/* Word */
+#define EEPROM_SOFT_INFO_2	0xf     /* Software information 2 */
+
+#define NO_RX_OVN_ANOMALY       (1<<5)
+
+/**************************************************************************
+ *										  *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable.  They have been taken out the the "EtherLink III Parallel  *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com.								  *
+ *										  *
+ **************************************************************************/
+
+#define VX_COMMAND		0x0e	/* Write. BASE+0x0e is always a
+					 * command reg. */
+#define VX_STATUS		0x0e	/* Read. BASE+0x0e is always status
+					 * reg. */
+#define VX_WINDOW		0x0f	/* Read. BASE+0x0f is always window
+					 * reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+/* Write */
+#define VX_W0_EEPROM_DATA	0x0c
+#define VX_W0_EEPROM_COMMAND	0x0a
+#define VX_W0_RESOURCE_CFG	0x08
+#define VX_W0_ADDRESS_CFG	0x06
+#define VX_W0_CONFIG_CTRL	0x04
+	/* Read */
+#define VX_W0_PRODUCT_ID	0x02
+#define VX_W0_MFG_ID		0x00
+
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+/* Write */
+#define VX_W1_TX_PIO_WR_2	0x02
+#define VX_W1_TX_PIO_WR_1	0x00
+/* Read */
+#define VX_W1_FREE_TX		0x0c
+#define VX_W1_TX_STATUS		0x0b	/* byte */
+#define VX_W1_TIMER		0x0a	/* byte */
+#define VX_W1_RX_STATUS		0x08
+#define VX_W1_RX_PIO_RD_2	0x02
+#define VX_W1_RX_PIO_RD_1	0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+/* Read/Write */
+#define VX_W2_ADDR_5		0x05
+#define VX_W2_ADDR_4		0x04
+#define VX_W2_ADDR_3		0x03
+#define VX_W2_ADDR_2		0x02
+#define VX_W2_ADDR_1		0x01
+#define VX_W2_ADDR_0		0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+/* Read */
+#define VX_W3_INTERNAL_CFG	0x00
+#define VX_W3_RESET_OPT		0x08
+#define VX_W3_FREE_TX		0x0c
+#define VX_W3_FREE_RX		0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+/* Read/Write */
+#define VX_W4_MEDIA_TYPE	0x0a
+#define VX_W4_CTRLR_STATUS	0x08
+#define VX_W4_NET_DIAG		0x06
+#define VX_W4_FIFO_DIAG		0x04
+#define VX_W4_HOST_DIAG		0x02
+#define VX_W4_TX_DIAG		0x00
+
+/*
+ * Window 5 Registers.  Results and Internal status.
+ */
+/* Read */
+#define VX_W5_READ_0_MASK	0x0c
+#define VX_W5_INTR_MASK		0x0a
+#define VX_W5_RX_FILTER		0x08
+#define VX_W5_RX_EARLY_THRESH	0x06
+#define VX_W5_TX_AVAIL_THRESH	0x02
+#define VX_W5_TX_START_THRESH	0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+/* Read/Write */
+#define TX_TOTAL_OK		0x0c
+#define RX_TOTAL_OK		0x0a
+#define TX_DEFERRALS		0x08
+#define RX_FRAMES_OK		0x07
+#define TX_FRAMES_OK		0x06
+#define RX_OVERRUNS		0x05
+#define TX_COLLISIONS		0x04
+#define TX_AFTER_1_COLLISION	0x03
+#define TX_AFTER_X_COLLISIONS	0x02
+#define TX_NO_SQE		0x01
+#define TX_CD_LOST		0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ *     15-11:  5-bit code for command to be executed.
+ *     10-0:   11-bit arg if any. For commands with no args;
+ *	      this can be set to anything.
+ */
+#define GLOBAL_RESET		(unsigned short) 0x0000	/* Wait at least 1ms
+							 * after issuing */
+#define WINDOW_SELECT		(unsigned short) (0x1<<11)
+#define START_TRANSCEIVER	(unsigned short) (0x2<<11)	/* Read ADDR_CFG reg to
+							 * determine whether
+							 * this is needed. If
+							 * so; wait 800 uSec
+							 * before using trans-
+							 * ceiver. */
+#define RX_DISABLE		(unsigned short) (0x3<<11)	/* state disabled on
+							 * power-up */
+#define RX_ENABLE		(unsigned short) (0x4<<11)
+#define RX_RESET		(unsigned short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK	(unsigned short) (0x8<<11)
+#define TX_ENABLE		(unsigned short) (0x9<<11)
+#define TX_DISABLE		(unsigned short) (0xa<<11)
+#define TX_RESET		(unsigned short) (0xb<<11)
+#define REQ_INTR		(unsigned short) (0xc<<11)
+/*
+ * The following C_* acknowledge the various interrupts. Some of them don't
+ * do anything.  See the manual.
+ */
+#define ACK_INTR		(unsigned short) (0x6800)
+#	define C_INTR_LATCH	(unsigned short) (ACK_INTR|0x1)
+#	define C_CARD_FAILURE	(unsigned short) (ACK_INTR|0x2)
+#	define C_TX_COMPLETE	(unsigned short) (ACK_INTR|0x4)
+#	define C_TX_AVAIL	(unsigned short) (ACK_INTR|0x8)
+#	define C_RX_COMPLETE	(unsigned short) (ACK_INTR|0x10)
+#	define C_RX_EARLY	(unsigned short) (ACK_INTR|0x20)
+#	define C_INT_RQD		(unsigned short) (ACK_INTR|0x40)
+#	define C_UPD_STATS	(unsigned short) (ACK_INTR|0x80)
+#define SET_INTR_MASK		(unsigned short) (0xe<<11)
+#define SET_RD_0_MASK		(unsigned short) (0xf<<11)
+#define SET_RX_FILTER		(unsigned short) (0x10<<11)
+#	define FIL_INDIVIDUAL	(unsigned short) (0x1)
+#	define FIL_MULTICAST     (unsigned short) (0x02)
+#	define FIL_BRDCST        (unsigned short) (0x04)
+#	define FIL_PROMISC       (unsigned short) (0x08)
+#define SET_RX_EARLY_THRESH	(unsigned short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH	(unsigned short) (0x12<<11)
+#define SET_TX_START_THRESH	(unsigned short) (0x13<<11)
+#define STATS_ENABLE		(unsigned short) (0x15<<11)
+#define STATS_DISABLE		(unsigned short) (0x16<<11)
+#define STOP_TRANSCEIVER	(unsigned short) (0x17<<11)
+
+/*
+ * Status register. All windows.
+ *
+ *     15-13:  Window number(0-7).
+ *     12:     Command_in_progress.
+ *     11:     reserved.
+ *     10:     reserved.
+ *     9:      reserved.
+ *     8:      reserved.
+ *     7:      Update Statistics.
+ *     6:      Interrupt Requested.
+ *     5:      RX Early.
+ *     4:      RX Complete.
+ *     3:      TX Available.
+ *     2:      TX Complete.
+ *     1:      Adapter Failure.
+ *     0:      Interrupt Latch.
+ */
+#define S_INTR_LATCH		(unsigned short) (0x1)
+#define S_CARD_FAILURE		(unsigned short) (0x2)
+#define S_TX_COMPLETE		(unsigned short) (0x4)
+#define S_TX_AVAIL		(unsigned short) (0x8)
+#define S_RX_COMPLETE		(unsigned short) (0x10)
+#define S_RX_EARLY		(unsigned short) (0x20)
+#define S_INT_RQD		(unsigned short) (0x40)
+#define S_UPD_STATS		(unsigned short) (0x80)
+#define S_COMMAND_IN_PROGRESS	(unsigned short) (0x1000)
+
+#define VX_BUSY_WAIT while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS)
+
+/* Address Config. Register.
+ * Window 0/Port 06
+ */
+
+#define ACF_CONNECTOR_BITS	14
+#define ACF_CONNECTOR_UTP	0
+#define ACF_CONNECTOR_AUI	1
+#define ACF_CONNECTOR_BNC	3
+
+#define INTERNAL_CONNECTOR_BITS 20
+#define INTERNAL_CONNECTOR_MASK 0x01700000
+
+/*
+ * FIFO Registers. RX Status.
+ *
+ *     15:     Incomplete or FIFO empty.
+ *     14:     1: Error in RX Packet   0: Incomplete or no error.
+ *     13-11:  Type of error.
+ *	      1000 = Overrun.
+ *	      1011 = Run Packet Error.
+ *	      1100 = Alignment Error.
+ *	      1101 = CRC Error.
+ *	      1001 = Oversize Packet Error (>1514 bytes)
+ *	      0010 = Dribble Bits.
+ *	      (all other error codes, no errors.)
+ *
+ *     10-0:   RX Bytes (0-1514)
+ */
+#define ERR_INCOMPLETE  (unsigned short) (0x8000)
+#define ERR_RX          (unsigned short) (0x4000)
+#define ERR_MASK        (unsigned short) (0x7800)
+#define ERR_OVERRUN     (unsigned short) (0x4000)
+#define ERR_RUNT        (unsigned short) (0x5800)
+#define ERR_ALIGNMENT   (unsigned short) (0x6000)
+#define ERR_CRC         (unsigned short) (0x6800)
+#define ERR_OVERSIZE    (unsigned short) (0x4800)
+#define ERR_DRIBBLE     (unsigned short) (0x1000)
+
+/*
+ * TX Status.
+ *
+ *   Reports the transmit status of a completed transmission. Writing this
+ *   register pops the transmit completion stack.
+ *
+ *   Window 1/Port 0x0b.
+ *
+ *     7:      Complete
+ *     6:      Interrupt on successful transmission requested.
+ *     5:      Jabber Error (TP Only, TX Reset required. )
+ *     4:      Underrun (TX Reset required. )
+ *     3:      Maximum Collisions.
+ *     2:      TX Status Overflow.
+ *     1-0:    Undefined.
+ *
+ */
+#define TXS_COMPLETE		0x80
+#define TXS_INTR_REQ		0x40
+#define TXS_JABBER		0x20
+#define TXS_UNDERRUN		0x10
+#define TXS_MAX_COLLISION	0x8
+#define TXS_STATUS_OVERFLOW	0x4
+
+#define RS_AUI			(1<<5)
+#define RS_BNC			(1<<4)
+#define RS_UTP			(1<<3)
+#define	RS_T4			(1<<0)
+#define	RS_TX			(1<<1)
+#define	RS_FX			(1<<2)
+#define	RS_MII			(1<<6)
+
+
+/*
+ * FIFO Status (Window 4)
+ *
+ *   Supports FIFO diagnostics
+ *
+ *   Window 4/Port 0x04.1
+ *
+ *     15:	1=RX receiving (RO). Set when a packet is being received
+ *		into the RX FIFO.
+ *     14:	Reserved
+ *     13:	1=RX underrun (RO). Generates Adapter Failure interrupt.
+ *		Requires RX Reset or Global Reset command to recover.
+ *		It is generated when you read past the end of a packet -
+ *		reading past what has been received so far will give bad
+ *		data.
+ *     12:	1=RX status overrun (RO). Set when there are already 8
+ *		packets in the RX FIFO. While this bit is set, no additional
+ *		packets are received. Requires no action on the part of
+ *		the host. The condition is cleared once a packet has been
+ *		read out of the RX FIFO.
+ *     11:	1=RX overrun (RO). Set when the RX FIFO is full (there
+ *		may not be an overrun packet yet). While this bit is set,
+ *		no additional packets will be received (some additional
+ *		bytes can still be pending between the wire and the RX
+ *		FIFO). Requires no action on the part of the host. The
+ *		condition is cleared once a few bytes have been read out
+ *		from the RX FIFO.
+ *     10:	1=TX overrun (RO). Generates adapter failure interrupt.
+ *		Requires TX Reset or Global Reset command to recover.
+ *		Disables Transmitter.
+ *     9-8:	Unassigned.
+ *     7-0:	Built in self test bits for the RX and TX FIFO's.
+ */
+#define FIFOS_RX_RECEIVING	(unsigned short) 0x8000
+#define FIFOS_RX_UNDERRUN	(unsigned short) 0x2000
+#define FIFOS_RX_STATUS_OVERRUN	(unsigned short) 0x1000
+#define FIFOS_RX_OVERRUN	(unsigned short) 0x0800
+#define FIFOS_TX_OVERRUN	(unsigned short) 0x0400
+
+/*
+ * Misc defines for various things.
+ */
+#define TAG_ADAPTER                     0xd0
+#define ACTIVATE_ADAPTER_TO_CONFIG      0xff
+#define ENABLE_DRQ_IRQ                  0x0001
+#define MFG_ID                          0x506d  /* `TCM' */
+#define PROD_ID                         0x5090
+#define GO_WINDOW(x)		outw(WINDOW_SELECT|(x),BASE+VX_COMMAND)
+#define JABBER_GUARD_ENABLE	0x40
+#define LINKBEAT_ENABLE		0x80
+#define	ENABLE_UTP		(JABBER_GUARD_ENABLE | LINKBEAT_ENABLE)
+#define DISABLE_UTP		0x0
+#define RX_BYTES_MASK		(unsigned short) (0x07ff)
+#define RX_ERROR        0x4000
+#define RX_INCOMPLETE   0x8000
+#define TX_INDICATE		1<<15
+#define is_eeprom_busy(b)	(inw((b)+VX_W0_EEPROM_COMMAND)&EEPROM_BUSY)
+
+#define	VX_IOSIZE	0x20
+
+#define VX_CONNECTORS 8
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/net/5701rls.c b/drivers/net/5701rls.c
new file mode 100644
index 0000000..86950d0
--- /dev/null
+++ b/drivers/net/5701rls.c
@@ -0,0 +1,46 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*                                                                            */
+/******************************************************************************/
+
+#if INCLUDE_5701_AX_FIX
+
+#include "bcm570x_mm.h"
+#include "5701rls.h"
+
+LM_STATUS LM_LoadRlsFirmware(PLM_DEVICE_BLOCK pDevice)
+{
+  T3_FWIMG_INFO FwImgInfo;
+
+  FwImgInfo.StartAddress = t3FwStartAddr;
+  FwImgInfo.Text.Buffer = (PLM_UINT8)t3FwText;
+  FwImgInfo.Text.Offset  = t3FwTextAddr;
+  FwImgInfo.Text.Length  = t3FwTextLen;
+  FwImgInfo.ROnlyData.Buffer = (PLM_UINT8)t3FwRodata;
+  FwImgInfo.ROnlyData.Offset  = t3FwRodataAddr;
+  FwImgInfo.ROnlyData.Length  = t3FwRodataLen;
+  FwImgInfo.Data.Buffer = (PLM_UINT8)t3FwData;
+  FwImgInfo.Data.Offset  = t3FwDataAddr;
+  FwImgInfo.Data.Length  = t3FwDataLen;
+
+  if (LM_LoadFirmware(pDevice,
+		      &FwImgInfo,
+		      T3_RX_CPU_ID | T3_TX_CPU_ID,
+		      T3_RX_CPU_ID) != LM_STATUS_SUCCESS)
+    {
+      return LM_STATUS_FAILURE;
+    }
+
+  return LM_STATUS_SUCCESS;
+}
+
+#endif /* INCLUDE_5701_AX_FIX */
diff --git a/drivers/net/5701rls.h b/drivers/net/5701rls.h
new file mode 100644
index 0000000..30b127a
--- /dev/null
+++ b/drivers/net/5701rls.h
@@ -0,0 +1,198 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/******************************************************************************/
+
+typedef unsigned long U32;
+int t3FwReleaseMajor = 0x0;
+int t3FwReleaseMinor = 0x0;
+int t3FwReleaseFix = 0x0;
+U32 t3FwStartAddr = 0x08000000;
+U32 t3FwTextAddr = 0x08000000;
+int t3FwTextLen = 0x9c0;
+U32 t3FwRodataAddr = 0x080009c0;
+int t3FwRodataLen = 0x60;
+U32 t3FwDataAddr = 0x08000a40;
+int t3FwDataLen = 0x20;
+U32 t3FwSbssAddr = 0x08000a60;
+int t3FwSbssLen = 0xc;
+U32 t3FwBssAddr = 0x08000a70;
+int t3FwBssLen = 0x10;
+U32 t3FwText[(0x9c0/4) + 1] = {
+0x0,
+0x10000003, 0x0, 0xd, 0xd,
+0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800,
+0x26100000, 0xe000018, 0x0, 0xd,
+0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800,
+0x26100034, 0xe00021c, 0x0, 0xd,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0x3c1cc000, 0xafbf0018, 0xaf80680c, 0xe00004c,
+0x241b2105, 0x97850000, 0x97870002, 0x9782002c,
+0x9783002e, 0x3c040800, 0x248409c0, 0xafa00014,
+0x21400, 0x621825, 0x52c00, 0xafa30010,
+0x8f860010, 0xe52825, 0xe000060, 0x24070102,
+0x3c02ac00, 0x34420100, 0x3c03ac01, 0x34630100,
+0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498,
+0xaf82049c, 0x24020001, 0xaf825ce0, 0xe00003f,
+0xaf825d00, 0xe000140, 0x0, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x2402ffff, 0xaf825404,
+0x8f835400, 0x34630400, 0xaf835400, 0xaf825404,
+0x3c020800, 0x24420034, 0xaf82541c, 0x3e00008,
+0xaf805400, 0x0, 0x0, 0x3c020800,
+0x34423000, 0x3c030800, 0x34633000, 0x3c040800,
+0x348437ff, 0x3c010800, 0xac220a64, 0x24020040,
+0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60,
+0xac600000, 0x24630004, 0x83102b, 0x5040fffd,
+0xac600000, 0x3e00008, 0x0, 0x804821,
+0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800,
+0x8c840a68, 0x8fab0014, 0x24430001, 0x44102b,
+0x3c010800, 0xac230a60, 0x14400003, 0x4021,
+0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60,
+0x3c030800, 0x8c630a64, 0x91240000, 0x21140,
+0x431021, 0x481021, 0x25080001, 0xa0440000,
+0x29020008, 0x1440fff4, 0x25290001, 0x3c020800,
+0x8c420a60, 0x3c030800, 0x8c630a64, 0x8f84680c,
+0x21140, 0x431021, 0xac440008, 0xac45000c,
+0xac460010, 0xac470014, 0xac4a0018, 0x3e00008,
+0xac4b001c, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2000008,
+0x0, 0xa0001e3, 0x3c0a0001, 0xa0001e3,
+0x3c0a0002, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x3c0a0007, 0xa0001e3, 0x3c0a0008, 0xa0001e3,
+0x3c0a0009, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x3c0a000b, 0xa0001e3,
+0x3c0a000c, 0xa0001e3, 0x3c0a000d, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x3c0a000e, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x0, 0xa0001e3,
+0x0, 0xa0001e3, 0x3c0a0013, 0xa0001e3,
+0x3c0a0014, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0x1821, 0x1021, 0xafbf0018, 0xafb10014,
+0xafb00010, 0x3c010800, 0x220821, 0xac200a70,
+0x3c010800, 0x220821, 0xac200a74, 0x3c010800,
+0x220821, 0xac200a78, 0x24630001, 0x1860fff5,
+0x2442000c, 0x24110001, 0x8f906810, 0x32020004,
+0x14400005, 0x24040001, 0x3c020800, 0x8c420a78,
+0x18400003, 0x2021, 0xe000182, 0x0,
+0x32020001, 0x10400003, 0x0, 0xe000169,
+0x0, 0xa000153, 0xaf915028, 0x8fbf0018,
+0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020,
+0x3c050800, 0x8ca50a70, 0x3c060800, 0x8cc60a80,
+0x3c070800, 0x8ce70a78, 0x27bdffe0, 0x3c040800,
+0x248409d0, 0xafbf0018, 0xafa00010, 0xe000060,
+0xafa00014, 0xe00017b, 0x2021, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x24020001, 0x8f836810,
+0x821004, 0x21027, 0x621824, 0x3e00008,
+0xaf836810, 0x27bdffd8, 0xafbf0024, 0x1080002e,
+0xafb00020, 0x8f825cec, 0xafa20018, 0x8f825cec,
+0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000,
+0xaf825cec, 0x8e020000, 0x18400016, 0x0,
+0x3c020800, 0x94420a74, 0x8fa3001c, 0x221c0,
+0xac830004, 0x8fa2001c, 0x3c010800, 0xe000201,
+0xac220a74, 0x10400005, 0x0, 0x8e020000,
+0x24420001, 0xa0001df, 0xae020000, 0x3c020800,
+0x8c420a70, 0x21c02, 0x321c0, 0xa0001c5,
+0xafa2001c, 0xe000201, 0x0, 0x1040001f,
+0x0, 0x8e020000, 0x8fa3001c, 0x24420001,
+0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74,
+0xa0001df, 0xae020000, 0x3c100800, 0x26100a78,
+0x8e020000, 0x18400028, 0x0, 0xe000201,
+0x0, 0x14400024, 0x0, 0x8e020000,
+0x3c030800, 0x8c630a70, 0x2442ffff, 0xafa3001c,
+0x18400006, 0xae020000, 0x31402, 0x221c0,
+0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e,
+0x2442ff00, 0x2c420300, 0x1440000b, 0x24024000,
+0x3c040800, 0x248409dc, 0xafa00010, 0xafa00014,
+0x8fa6001c, 0x24050008, 0xe000060, 0x3821,
+0xa0001df, 0x0, 0xaf825cf8, 0x3c020800,
+0x8c420a40, 0x8fa3001c, 0x24420001, 0xaf835cf8,
+0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020,
+0x3e00008, 0x27bd0028, 0x27bdffe0, 0x3c040800,
+0x248409e8, 0x2821, 0x3021, 0x3821,
+0xafbf0018, 0xafa00010, 0xe000060, 0xafa00014,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f82680c,
+0x8f85680c, 0x21827, 0x3182b, 0x31823,
+0x431024, 0x441021, 0xa2282b, 0x10a00006,
+0x0, 0x401821, 0x8f82680c, 0x43102b,
+0x1440fffd, 0x0, 0x3e00008, 0x0,
+0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40,
+0x64102b, 0x54400002, 0x831023, 0x641023,
+0x2c420008, 0x3e00008, 0x38420001, 0x27bdffe0,
+0x802821, 0x3c040800, 0x24840a00, 0x3021,
+0x3821, 0xafbf0018, 0xafa00010, 0xe000060,
+0xafa00014, 0xa000216, 0x0, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x0, 0x27bdffe0,
+0x3c1cc000, 0xafbf0018, 0xe00004c, 0xaf80680c,
+0x3c040800, 0x24840a10, 0x3802821, 0x3021,
+0x3821, 0xafa00010, 0xe000060, 0xafa00014,
+0x2402ffff, 0xaf825404, 0x3c0200aa, 0xe000234,
+0xaf825434, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x0, 0x0, 0x0, 0x27bdffe8,
+0xafb00010, 0x24100001, 0xafbf0014, 0x3c01c003,
+0xac200000, 0x8f826810, 0x30422000, 0x10400003,
+0x0, 0xe000246, 0x0, 0xa00023a,
+0xaf905428, 0x8fbf0014, 0x8fb00010, 0x3e00008,
+0x27bd0018, 0x27bdfff8, 0x8f845d0c, 0x3c0200ff,
+0x3c030800, 0x8c630a50, 0x3442fff8, 0x821024,
+0x1043001e, 0x3c0500ff, 0x34a5fff8, 0x3c06c003,
+0x3c074000, 0x851824, 0x8c620010, 0x3c010800,
+0xac230a50, 0x30420008, 0x10400005, 0x871025,
+0x8cc20000, 0x24420001, 0xacc20000, 0x871025,
+0xaf825d0c, 0x8fa20000, 0x24420001, 0xafa20000,
+0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000,
+0x8fa20000, 0x8f845d0c, 0x3c030800, 0x8c630a50,
+0x851024, 0x1443ffe8, 0x851824, 0x27bd0008,
+0x3e00008, 0x0, 0x0, 0x0 };
+U32 t3FwRodata[(0x60/4) + 1] = {
+0x35373031, 0x726c7341, 0x0,
+0x0, 0x53774576, 0x656e7430, 0x0,
+0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e,
+0x45766e74, 0x0, 0x0, 0x0,
+0x0, 0x66617461, 0x6c457272, 0x0,
+0x0, 0x4d61696e, 0x43707542, 0x0,
+0x0, 0x0 };
+U32 t3FwData[(0x20/4) + 1] = {
+0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0 };
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
new file mode 100644
index 0000000..f087217
--- /dev/null
+++ b/drivers/net/8390.h
@@ -0,0 +1,124 @@
+/*
+
+Ported to U-Boot  by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+*/
+
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+   Some of these names and comments originated from the Crynwr
+   packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK	0x5
+#define E8390_RXCONFIG		0x4	/* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
+
+/*  Register accessed at EN_CMD, the 8390 base addr.  */
+#define E8390_STOP	0x01	/* Stop and reset the chip */
+#define E8390_START	0x02	/* Start the chip, clear reset */
+#define E8390_TRANS	0x04	/* Transmit a frame */
+#define E8390_RREAD	0x08	/* Remote read */
+#define E8390_RWRITE	0x10	/* Remote write  */
+#define E8390_NODMA	0x20	/* Remote DMA */
+#define E8390_PAGE0	0x00	/* Select page chip registers */
+#define E8390_PAGE1	0x40	/* using the two high-order bits */
+#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
+
+/*
+ *	Only generate indirect loads given a machine that needs them.
+ *      - removed AMIGA_PCMCIA from this list, handled as ISA io now
+ */
+
+#define n2k_inb(port)   (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)))
+#define n2k_outb(val,port)  (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)) = val)
+
+#define EI_SHIFT(x)	(x)
+
+#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
+#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
+#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
+#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
+#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
+#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
+#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
+#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
+#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
+#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
+#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
+#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
+#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
+#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
+#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
+#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
+#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
+#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
+#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
+#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
+#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
+#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
+#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
+#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
+#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX	0x01	/* Receiver, no error */
+#define ENISR_TX	0x02	/* Transmitter, no error */
+#define ENISR_RX_ERR	0x04	/* Receiver, with error */
+#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
+#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
+#define ENISR_COUNTERS	0x20	/* Counters need emptying */
+#define ENISR_RDC	0x40	/* remote dma complete */
+#define ENISR_RESET	0x80	/* Reset completed */
+#define ENISR_ALL	0x3f	/* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS	0x01	/* word transfer mode selection */
+#define ENDCFG_BOS	0x02	/* byte order selection */
+#define ENDCFG_AUTO_INIT   0x10        /* Auto-init to remove packets from ring */
+#define ENDCFG_FIFO		0x40	/* 8 bytes */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
+#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK	0x01	/* Received a good packet */
+#define ENRSR_CRC	0x02	/* CRC error */
+#define ENRSR_FAE	0x04	/* frame alignment error */
+#define ENRSR_FO	0x08	/* FIFO overrun */
+#define ENRSR_MPA	0x10	/* missed pkt */
+#define ENRSR_PHY	0x20	/* physical/multicast address */
+#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
+#define ENRSR_DEF	0x80	/* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01	/* Packet transmitted without error */
+#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04	/* The transmit collided at least once. */
+#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
+
+#define NIC_RECEIVE_MONITOR_MODE 0x20
+
+#endif /* _8390_h */
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 37d69b9..41e1bde 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -25,8 +25,39 @@
 
 LIB 	:= $(obj)libnet.a
 
-COBJS 	:= mcffec.o
+COBJS-y += 3c589.o
+COBJS-y += bcm570x.o bcm570x_autoneg.o 5701rls.o
+COBJS-y += cs8900.o
+COBJS-y += dc2114x.o
+COBJS-y += dm9000x.o
+COBJS-y += e1000.o
+COBJS-y += eepro100.o
+COBJS-y += enc28j60.o
+COBJS-y += inca-ip_sw.o
+COBJS-y += ks8695eth.o
+COBJS-y += lan91c96.o
+COBJS-y += macb.o
+COBJS-y += mcffec.o
+COBJS-y += natsemi.o
+COBJS-y += ne2000.o
+COBJS-y += netarm_eth.o
+COBJS-y += netconsole.o
+COBJS-y += ns7520_eth.o
+COBJS-y += ns8382x.o
+COBJS-y += ns9750_eth.o
+COBJS-y += pcnet.o
+COBJS-y += plb2800_eth.o
+COBJS-y += rtl8019.o
+COBJS-y += rtl8139.o
+COBJS-y += rtl8169.o
+COBJS-y += s3c4510b_eth.o
+COBJS-y += smc91111.o
+COBJS-y += tigon3.o
+COBJS-y += tsec.o
+COBJS-y += tsi108_eth.o
+COBJS-y += uli526x.o
 
+COBJS	:= $(COBJS-y)
 SRCS 	:= $(COBJS:.o=.c)
 OBJS 	:= $(addprefix $(obj),$(COBJS))
 
diff --git a/drivers/net/bcm570x.c b/drivers/net/bcm570x.c
new file mode 100644
index 0000000..c8f4064
--- /dev/null
+++ b/drivers/net/bcm570x.c
@@ -0,0 +1,1603 @@
+/*
+ * Broadcom BCM570x Ethernet Driver for U-Boot.
+ * Support 5701, 5702, 5703, and 5704. Single instance driver.
+ * Copyright (C) 2002 James F. Dougherty (jfd@broadcom.com)
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x)
+
+#ifdef CONFIG_BMW
+#include <mpc824x.h>
+#endif
+#include <net.h>
+#include "bcm570x_mm.h"
+#include "bcm570x_autoneg.h"
+#include <pci.h>
+#include <malloc.h>
+
+/*
+ * PCI Registers and definitions.
+ */
+#define PCI_CMD_MASK	0xffff0000	/* mask to save status bits */
+#define PCI_ANY_ID (~0)
+
+/*
+ * PCI memory base for Ethernet device as well as device Interrupt.
+ */
+#define BCM570X_MBAR 	0x80100000
+#define BCM570X_ILINE   1
+
+#define SECOND_USEC	1000000
+#define MAX_PACKET_SIZE 1600
+#define MAX_UNITS       4
+
+/* Globals to this module */
+int initialized = 0;
+unsigned int ioBase = 0;
+volatile PLM_DEVICE_BLOCK pDevice = NULL;	/* 570x softc */
+volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
+
+/* Used to pass the full-duplex flag, etc. */
+int line_speed[MAX_UNITS] = { 0, 0, 0, 0 };
+static int full_duplex[MAX_UNITS] = { 1, 1, 1, 1 };
+static int rx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
+static int tx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
+static int auto_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
+static int tx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
+static int rx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
+static int auto_speed[MAX_UNITS] = { 1, 1, 1, 1 };
+
+#if JUMBO_FRAMES
+/* Jumbo MTU for interfaces. */
+static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
+#endif
+
+/* Turn on Wake-on lan for a device unit */
+static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
+
+#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
+static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
+    { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };
+
+#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
+static unsigned int rx_std_desc_cnt[MAX_UNITS] =
+    { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };
+
+static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
+static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
+    { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };
+#endif
+#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
+static unsigned int rx_coalesce_ticks[MAX_UNITS] =
+    { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };
+
+#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
+static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
+    { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };
+
+#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
+static unsigned int tx_coalesce_ticks[MAX_UNITS] =
+    { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };
+
+#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
+static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
+    { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };
+
+#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
+static unsigned int stats_coalesce_ticks[MAX_UNITS] =
+    { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };
+
+/*
+ * Legitimate values for BCM570x device types
+ */
+typedef enum {
+	BCM5700VIGIL = 0,
+	BCM5700A6,
+	BCM5700T6,
+	BCM5700A9,
+	BCM5700T9,
+	BCM5700,
+	BCM5701A5,
+	BCM5701T1,
+	BCM5701T8,
+	BCM5701A7,
+	BCM5701A10,
+	BCM5701A12,
+	BCM5701,
+	BCM5702,
+	BCM5703,
+	BCM5703A31,
+	TC996T,
+	TC996ST,
+	TC996SSX,
+	TC996SX,
+	TC996BT,
+	TC997T,
+	TC997SX,
+	TC1000T,
+	TC940BR01,
+	TC942BR01,
+	NC6770,
+	NC7760,
+	NC7770,
+	NC7780
+} board_t;
+
+/* Chip-Rev names for each device-type */
+static struct {
+	char *name;
+} chip_rev[] = {
+	{
+	"BCM5700VIGIL"}, {
+	"BCM5700A6"}, {
+	"BCM5700T6"}, {
+	"BCM5700A9"}, {
+	"BCM5700T9"}, {
+	"BCM5700"}, {
+	"BCM5701A5"}, {
+	"BCM5701T1"}, {
+	"BCM5701T8"}, {
+	"BCM5701A7"}, {
+	"BCM5701A10"}, {
+	"BCM5701A12"}, {
+	"BCM5701"}, {
+	"BCM5702"}, {
+	"BCM5703"}, {
+	"BCM5703A31"}, {
+	"TC996T"}, {
+	"TC996ST"}, {
+	"TC996SSX"}, {
+	"TC996SX"}, {
+	"TC996BT"}, {
+	"TC997T"}, {
+	"TC997SX"}, {
+	"TC1000T"}, {
+	"TC940BR01"}, {
+	"TC942BR01"}, {
+	"NC6770"}, {
+	"NC7760"}, {
+	"NC7770"}, {
+	"NC7780"}, {
+	0}
+};
+
+/* indexed by board_t, above */
+static struct {
+	char *name;
+} board_info[] = {
+	{
+	"Broadcom Vigil B5700 1000Base-T"}, {
+	"Broadcom BCM5700 1000Base-T"}, {
+	"Broadcom BCM5700 1000Base-SX"}, {
+	"Broadcom BCM5700 1000Base-SX"}, {
+	"Broadcom BCM5700 1000Base-T"}, {
+	"Broadcom BCM5700"}, {
+	"Broadcom BCM5701 1000Base-T"}, {
+	"Broadcom BCM5701 1000Base-T"}, {
+	"Broadcom BCM5701 1000Base-T"}, {
+	"Broadcom BCM5701 1000Base-SX"}, {
+	"Broadcom BCM5701 1000Base-T"}, {
+	"Broadcom BCM5701 1000Base-T"}, {
+	"Broadcom BCM5701"}, {
+	"Broadcom BCM5702 1000Base-T"}, {
+	"Broadcom BCM5703 1000Base-T"}, {
+	"Broadcom BCM5703 1000Base-SX"}, {
+	"3Com 3C996 10/100/1000 Server NIC"}, {
+	"3Com 3C996 10/100/1000 Server NIC"}, {
+	"3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
+	"3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
+	"3Com 3C996B Gigabit Server NIC"}, {
+	"3Com 3C997 Gigabit Server NIC"}, {
+	"3Com 3C997 Gigabit Fiber-SX Server NIC"}, {
+	"3Com 3C1000 Gigabit NIC"}, {
+	"3Com 3C940 Gigabit LOM (21X21)"}, {
+	"3Com 3C942 Gigabit LOM (31X31)"}, {
+	"Compaq NC6770 Gigabit Server Adapter"}, {
+	"Compaq NC7760 Gigabit Server Adapter"}, {
+	"Compaq NC7770 Gigabit Server Adapter"}, {
+	"Compaq NC7780 Gigabit Server Adapter"}, {
+0},};
+
+/* PCI Devices which use the 570x chipset */
+struct pci_device_table {
+	unsigned short vendor_id, device_id;	/* Vendor/DeviceID */
+	unsigned short subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
+	unsigned int class, class_mask;	/* (class,subclass,prog-if) triplet */
+	unsigned long board_id;	/* Data private to the driver */
+	int io_size, min_latency;
+} bcm570xDevices[] = {
+	{
+	0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL, 128, 32}, {
+	0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6, 128, 32}, {
+	0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6, 128, 32}, {
+	0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9, 128, 32}, {
+	0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9, 128, 32}, {
+	0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700, 128, 32}, {
+	0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700, 128, 32}, {
+	0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700, 128, 32}, {
+	0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX, 128, 32}, {
+	0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01, 128, 32}, {
+	0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10, 128, 32}, {
+	0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12, 128, 32}, {
+	0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770, 128, 32}, {
+	0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770, 128, 32}, {
+	0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780, 128, 32}, {
+	0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701, 128, 32}, {
+	0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX, 128, 32}, {
+	0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT, 128, 32}, {
+	0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T, 128, 32}, {
+	0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01, 128, 32}, {
+	0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701, 128, 32}, {
+	0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
+	0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
+	0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
+	0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
+	0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
+	0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
+	0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
+	0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
+	0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
+	0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
+	0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
+	0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
+	0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
+	0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}
+};
+
+#define n570xDevices   (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
+
+/*
+ * Allocate a packet buffer from the bcm570x packet pool.
+ */
+void *bcm570xPktAlloc (int u, int pksize)
+{
+	return malloc (pksize);
+}
+
+/*
+ * Free a packet previously allocated from the bcm570x packet
+ * buffer pool.
+ */
+void bcm570xPktFree (int u, void *p)
+{
+	free (p);
+}
+
+int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
+{
+	PLM_PACKET pPacket;
+	PUM_PACKET pUmPacket;
+	void *skb;
+	int queue_rx = 0;
+	int ret = 0;
+
+	while ((pUmPacket = (PUM_PACKET)
+		QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
+
+		pPacket = (PLM_PACKET) pUmPacket;
+
+		/* reuse an old skb */
+		if (pUmPacket->skbuff) {
+			QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
+				     pPacket);
+			queue_rx = 1;
+			continue;
+		}
+		if ((skb = bcm570xPktAlloc (pUmDevice->index,
+					    pPacket->u.Rx.RxBufferSize + 2)) ==
+		    0) {
+			QQ_PushHead (&pUmDevice->rx_out_of_buf_q.Container,
+				     pPacket);
+			printf ("NOTICE: Out of RX memory.\n");
+			ret = 1;
+			break;
+		}
+
+		pUmPacket->skbuff = skb;
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+		queue_rx = 1;
+	}
+
+	if (queue_rx) {
+		LM_QueueRxPackets (pDevice);
+	}
+
+	return ret;
+}
+
+/*
+ * Probe, Map, and Init 570x device.
+ */
+int eth_init (bd_t * bis)
+{
+	int i, rv, devFound = FALSE;
+	pci_dev_t devbusfn;
+	unsigned short status;
+
+	/* Find PCI device, if it exists, configure ...  */
+	for (i = 0; i < n570xDevices; i++) {
+		devbusfn = pci_find_device (bcm570xDevices[i].vendor_id,
+					    bcm570xDevices[i].device_id, 0);
+		if (devbusfn == -1) {
+			continue;	/* No device of that vendor/device ID */
+		} else {
+
+			/* Set ILINE */
+			pci_write_config_byte (devbusfn,
+					       PCI_INTERRUPT_LINE,
+					       BCM570X_ILINE);
+
+			/*
+			 * 0x10 - 0x14 define one 64-bit MBAR.
+			 * 0x14 is the higher-order address bits of the BAR.
+			 */
+			pci_write_config_dword (devbusfn,
+						PCI_BASE_ADDRESS_1, 0);
+
+			ioBase = BCM570X_MBAR;
+
+			pci_write_config_dword (devbusfn,
+						PCI_BASE_ADDRESS_0, ioBase);
+
+			/*
+			 * Enable PCI memory, IO, and Master -- don't
+			 * reset any status bits in doing so.
+			 */
+			pci_read_config_word (devbusfn, PCI_COMMAND, &status);
+
+			status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+
+			pci_write_config_word (devbusfn, PCI_COMMAND, status);
+
+			printf
+			    ("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n",
+			     board_info[bcm570xDevices[i].board_id].name,
+			     PCI_BUS (devbusfn), PCI_DEV (devbusfn),
+			     PCI_FUNC (devbusfn), ioBase);
+
+			/* Allocate once, but always clear on init */
+			if (!pDevice) {
+				pDevice = malloc (sizeof (UM_DEVICE_BLOCK));
+				pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+				memset (pDevice, 0x0, sizeof (UM_DEVICE_BLOCK));
+			}
+
+			/* Configure pci dev structure */
+			pUmDevice->pdev = devbusfn;
+			pUmDevice->index = 0;
+			pUmDevice->tx_pkt = 0;
+			pUmDevice->rx_pkt = 0;
+			devFound = TRUE;
+			break;
+		}
+	}
+
+	if (!devFound) {
+		printf
+		    ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
+		return -1;
+	}
+
+	/* Setup defaults for chip */
+	pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
+
+	if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
+		pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
+	} else {
+
+		if (rx_checksum[i]) {
+			pDevice->TaskToOffload |=
+			    LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
+			    LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
+		}
+
+		if (tx_checksum[i]) {
+			pDevice->TaskToOffload |=
+			    LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
+			    LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
+			pDevice->NoTxPseudoHdrChksum = TRUE;
+		}
+	}
+
+	/* Set Device PCI Memory base address */
+	pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
+
+	/* Pull down adapter info */
+	if ((rv = LM_GetAdapterInfo (pDevice)) != LM_STATUS_SUCCESS) {
+		printf ("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv);
+		return -2;
+	}
+
+	/* Lock not needed */
+	pUmDevice->do_global_lock = 0;
+
+	if (T3_ASIC_REV (pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
+		/* The 5700 chip works best without interleaved register */
+		/* accesses on certain machines. */
+		pUmDevice->do_global_lock = 1;
+	}
+
+	/* Setup timer delays */
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+		pDevice->UseTaggedStatus = TRUE;
+		pUmDevice->timer_interval = CFG_HZ;
+	} else {
+		pUmDevice->timer_interval = CFG_HZ / 50;
+	}
+
+	/* Grab name .... */
+	pUmDevice->name =
+	    (char *)malloc (strlen (board_info[bcm570xDevices[i].board_id].name)
+			    + 1);
+	strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
+
+	memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6);
+	LM_SetMacAddress (pDevice, bis->bi_enetaddr);
+	/* Init queues  .. */
+	QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
+		      MAX_RX_PACKET_DESC_COUNT);
+	pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
+
+	/* delay for 4 seconds */
+	pUmDevice->delayed_link_ind = (4 * CFG_HZ) / pUmDevice->timer_interval;
+
+	pUmDevice->adaptive_expiry = CFG_HZ / pUmDevice->timer_interval;
+
+	/* Sometimes we get spurious ints. after reset when link is down. */
+	/* This field tells the isr to service the int. even if there is */
+	/* no status block update. */
+	pUmDevice->adapter_just_inited =
+	    (3 * CFG_HZ) / pUmDevice->timer_interval;
+
+	/* Initialize 570x */
+	if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
+		printf ("ERROR: Adapter initialization failed.\n");
+		return ERROR;
+	}
+
+	/* Enable chip ISR */
+	LM_EnableInterrupt (pDevice);
+
+	/* Clear MC table */
+	LM_MulticastClear (pDevice);
+
+	/* Enable Multicast */
+	LM_SetReceiveMask (pDevice,
+			   pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
+
+	pUmDevice->opened = 1;
+	pUmDevice->tx_full = 0;
+	pUmDevice->tx_pkt = 0;
+	pUmDevice->rx_pkt = 0;
+	printf ("eth%d: %s @0x%lx,",
+		pDevice->index, pUmDevice->name, (unsigned long)ioBase);
+	printf ("node addr ");
+	for (i = 0; i < 6; i++) {
+		printf ("%2.2x", pDevice->NodeAddress[i]);
+	}
+	printf ("\n");
+
+	printf ("eth%d: ", pDevice->index);
+	printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
+
+	if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
+		printf ("Broadcom BCM5400 Copper ");
+	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
+		printf ("Broadcom BCM5401 Copper ");
+	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
+		printf ("Broadcom BCM5411 Copper ");
+	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID)
+		printf ("Broadcom BCM5701 Integrated Copper ");
+	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID)
+		printf ("Broadcom BCM5703 Integrated Copper ");
+	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
+		printf ("Broadcom BCM8002 SerDes ");
+	else if (pDevice->EnableTbi)
+		printf ("Agilent HDMP-1636 SerDes ");
+	else
+		printf ("Unknown ");
+	printf ("transceiver found\n");
+
+	printf ("eth%d: %s, MTU: %d,",
+		pDevice->index, pDevice->BusSpeedStr, 1500);
+
+	if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && rx_checksum[i])
+		printf ("Rx Checksum ON\n");
+	else
+		printf ("Rx Checksum OFF\n");
+	initialized++;
+
+	return 0;
+}
+
+/* Ethernet Interrupt service routine */
+void eth_isr (void)
+{
+	LM_UINT32 oldtag, newtag;
+	int i;
+
+	pUmDevice->interrupt = 1;
+
+	if (pDevice->UseTaggedStatus) {
+		if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
+		    pUmDevice->adapter_just_inited) {
+			MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 1);
+			oldtag = pDevice->pStatusBlkVirt->StatusTag;
+
+			for (i = 0;; i++) {
+				pDevice->pStatusBlkVirt->Status &=
+				    ~STATUS_BLOCK_UPDATED;
+				LM_ServiceInterrupts (pDevice);
+				newtag = pDevice->pStatusBlkVirt->StatusTag;
+				if ((newtag == oldtag) || (i > 50)) {
+					MB_REG_WR (pDevice,
+						   Mailbox.Interrupt[0].Low,
+						   newtag << 24);
+					if (pDevice->UndiFix) {
+						REG_WR (pDevice, Grc.LocalCtrl,
+							pDevice->
+							GrcLocalCtrl | 0x2);
+					}
+					break;
+				}
+				oldtag = newtag;
+			}
+		}
+	} else {
+		while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
+			unsigned int dummy;
+
+			pDevice->pMemView->Mailbox.Interrupt[0].Low = 1;
+			pDevice->pStatusBlkVirt->Status &=
+			    ~STATUS_BLOCK_UPDATED;
+			LM_ServiceInterrupts (pDevice);
+			pDevice->pMemView->Mailbox.Interrupt[0].Low = 0;
+			dummy = pDevice->pMemView->Mailbox.Interrupt[0].Low;
+		}
+	}
+
+	/* Allocate new RX buffers */
+	if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
+		bcm570xReplenishRxBuffers (pUmDevice);
+	}
+
+	/* Queue packets */
+	if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
+		LM_QueueRxPackets (pDevice);
+	}
+
+	if (pUmDevice->tx_queued) {
+		pUmDevice->tx_queued = 0;
+	}
+
+	if (pUmDevice->tx_full) {
+		if (pDevice->LinkStatus != LM_STATUS_LINK_DOWN) {
+			printf
+			    ("NOTICE: tx was previously blocked, restarting MUX\n");
+			pUmDevice->tx_full = 0;
+		}
+	}
+
+	pUmDevice->interrupt = 0;
+
+}
+
+int eth_send (volatile void *packet, int length)
+{
+	int status = 0;
+#if ET_DEBUG
+	unsigned char *ptr = (unsigned char *)packet;
+#endif
+	PLM_PACKET pPacket;
+	PUM_PACKET pUmPacket;
+
+	/* Link down, return */
+	while (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
+#if 0
+		printf ("eth%d: link down - check cable or link partner.\n",
+			pUmDevice->index);
+#endif
+		eth_isr ();
+
+		/* Wait to see link for one-half a second before sending ... */
+		udelay (1500000);
+
+	}
+
+	/* Clear sent flag */
+	pUmDevice->tx_pkt = 0;
+
+	/* Previously blocked */
+	if (pUmDevice->tx_full) {
+		printf ("eth%d: tx blocked.\n", pUmDevice->index);
+		return 0;
+	}
+
+	pPacket = (PLM_PACKET)
+	    QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
+
+	if (pPacket == 0) {
+		pUmDevice->tx_full = 1;
+		printf ("bcm570xEndSend: TX full!\n");
+		return 0;
+	}
+
+	if (pDevice->SendBdLeft.counter == 0) {
+		pUmDevice->tx_full = 1;
+		printf ("bcm570xEndSend: no more TX descriptors!\n");
+		QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
+		return 0;
+	}
+
+	if (length <= 0) {
+		printf ("eth: bad packet size: %d\n", length);
+		goto out;
+	}
+
+	/* Get packet buffers and fragment list */
+	pUmPacket = (PUM_PACKET) pPacket;
+	/* Single DMA Descriptor transmit.
+	 * Fragments may be provided, but one DMA descriptor max is
+	 * used to send the packet.
+	 */
+	if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
+		if (pUmPacket->skbuff == NULL) {
+			/* Packet was discarded */
+			printf ("TX: failed (1)\n");
+			status = 1;
+		} else {
+			printf ("TX: failed (2)\n");
+			status = 2;
+		}
+		QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
+		return status;
+	}
+
+	/* Copy packet to DMA buffer */
+	memset (pUmPacket->skbuff, 0x0, MAX_PACKET_SIZE);
+	memcpy ((void *)pUmPacket->skbuff, (void *)packet, length);
+	pPacket->PacketSize = length;
+	pPacket->Flags |= SND_BD_FLAG_END | SND_BD_FLAG_COAL_NOW;
+	pPacket->u.Tx.FragCount = 1;
+	/* We've already provided a frame ready for transmission */
+	pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
+
+	if (LM_SendPacket (pDevice, pPacket) == LM_STATUS_FAILURE) {
+		/*
+		 *  A lower level send failure will push the packet descriptor back
+		 *  in the free queue, so just deal with the VxWorks clusters.
+		 */
+		if (pUmPacket->skbuff == NULL) {
+			printf ("TX failed (1)!\n");
+			/* Packet was discarded */
+			status = 3;
+		} else {
+			/* A resource problem ... */
+			printf ("TX failed (2)!\n");
+			status = 4;
+		}
+
+		if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
+			printf ("TX: emptyQ!\n");
+			pUmDevice->tx_full = 1;
+		}
+	}
+
+	while (pUmDevice->tx_pkt == 0) {
+		/* Service TX */
+		eth_isr ();
+	}
+#if ET_DEBUG
+	printf ("eth_send: 0x%x, %d bytes\n"
+		"[%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x] ...\n",
+		(int)pPacket, length,
+		ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
+		ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
+		ptr[13], ptr[14], ptr[15]);
+#endif
+	pUmDevice->tx_pkt = 0;
+	QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
+
+	/* Done with send */
+      out:
+	return status;
+}
+
+/* Ethernet receive */
+int eth_rx (void)
+{
+	PLM_PACKET pPacket = NULL;
+	PUM_PACKET pUmPacket = NULL;
+	void *skb;
+	int size = 0;
+
+	while (TRUE) {
+
+	      bcm570x_service_isr:
+		/* Pull down packet if it is there */
+		eth_isr ();
+
+		/* Indicate RX packets called */
+		if (pUmDevice->rx_pkt) {
+			/* printf("eth_rx: got a packet...\n"); */
+			pUmDevice->rx_pkt = 0;
+		} else {
+			/* printf("eth_rx: waiting for packet...\n"); */
+			goto bcm570x_service_isr;
+		}
+
+		pPacket = (PLM_PACKET)
+		    QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
+
+		if (pPacket == 0) {
+			printf ("eth_rx: empty packet!\n");
+			goto bcm570x_service_isr;
+		}
+
+		pUmPacket = (PUM_PACKET) pPacket;
+#if ET_DEBUG
+		printf ("eth_rx: packet @0x%x\n", (int)pPacket);
+#endif
+		/* If the packet generated an error, reuse buffer */
+		if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
+		    ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
+
+			/* reuse skb */
+			QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
+				     pPacket);
+			printf ("eth_rx: error in packet dma!\n");
+			goto bcm570x_service_isr;
+		}
+
+		/* Set size and address */
+		skb = pUmPacket->skbuff;
+		size = pPacket->PacketSize;
+
+		/* Pass the packet up to the protocol
+		 * layers.
+		 */
+		NetReceive (skb, size);
+
+		/* Free packet buffer */
+		bcm570xPktFree (pUmDevice->index, skb);
+		pUmPacket->skbuff = NULL;
+
+		/* Reuse SKB */
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+
+		return 0;	/* Got a packet, bail ... */
+	}
+	return size;
+}
+
+/* Shut down device */
+void eth_halt (void)
+{
+	int i;
+	if (initialized)
+		if (pDevice && pUmDevice && pUmDevice->opened) {
+			printf ("\neth%d:%s,", pUmDevice->index,
+				pUmDevice->name);
+			printf ("HALT,");
+			/* stop device */
+			LM_Halt (pDevice);
+			printf ("POWER DOWN,");
+			LM_SetPowerState (pDevice, LM_POWER_STATE_D3);
+
+			/* Free the memory allocated by the device in tigon3 */
+			for (i = 0; i < pUmDevice->mem_list_num; i++) {
+				if (pUmDevice->mem_list[i]) {
+					/* sanity check */
+					if (pUmDevice->dma_list[i]) {	/* cache-safe memory */
+						free (pUmDevice->mem_list[i]);
+					} else {
+						free (pUmDevice->mem_list[i]);	/* normal memory   */
+					}
+				}
+			}
+			pUmDevice->opened = 0;
+			free (pDevice);
+			pDevice = NULL;
+			pUmDevice = NULL;
+			initialized = 0;
+			printf ("done - offline.\n");
+		}
+}
+
+/*
+ *
+ * Middle Module: Interface between the HW driver (tigon3 modules) and
+ * the native (SENS) driver.  These routines implement the system
+ * interface for tigon3 on VxWorks.
+ */
+
+/* Middle module dependency - size of a packet descriptor */
+int MM_Packet_Desc_Size = sizeof (UM_PACKET);
+
+LM_STATUS
+MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
+		 LM_UINT32 Offset, LM_UINT32 * pValue32)
+{
+	UM_DEVICE_BLOCK *pUmDevice;
+	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
+	pci_read_config_dword (pUmDevice->pdev, Offset, (u32 *) pValue32);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS
+MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
+{
+	UM_DEVICE_BLOCK *pUmDevice;
+	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
+	pci_write_config_dword (pUmDevice->pdev, Offset, Value32);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS
+MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
+		 LM_UINT32 Offset, LM_UINT16 * pValue16)
+{
+	UM_DEVICE_BLOCK *pUmDevice;
+	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
+	pci_read_config_word (pUmDevice->pdev, Offset, (u16 *) pValue16);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS
+MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
+{
+	UM_DEVICE_BLOCK *pUmDevice;
+	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
+	pci_write_config_word (pUmDevice->pdev, Offset, Value16);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS
+MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
+			 PLM_VOID * pMemoryBlockVirt,
+			 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
+{
+	PLM_VOID pvirt;
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	dma_addr_t mapping;
+
+	pvirt = malloc (BlockSize);
+	mapping = (dma_addr_t) (pvirt);
+	if (!pvirt)
+		return LM_STATUS_FAILURE;
+
+	pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
+	pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
+	pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
+	memset (pvirt, 0, BlockSize);
+
+	*pMemoryBlockVirt = (PLM_VOID) pvirt;
+	MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
+
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS
+MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
+		   PLM_VOID * pMemoryBlockVirt)
+{
+	PLM_VOID pvirt;
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+
+	pvirt = malloc (BlockSize);
+
+	if (!pvirt)
+		return LM_STATUS_FAILURE;
+
+	pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
+	pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
+	pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
+	memset (pvirt, 0, BlockSize);
+	*pMemoryBlockVirt = pvirt;
+
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
+{
+	printf ("BCM570x PCI Memory base address @0x%x\n",
+		(unsigned int)pDevice->pMappedMemBase);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
+{
+	int i;
+	void *skb;
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	PUM_PACKET pUmPacket = NULL;
+	PLM_PACKET pPacket = NULL;
+
+	for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
+		pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
+		pUmPacket = (PUM_PACKET) pPacket;
+
+		if (pPacket == 0) {
+			printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
+		}
+
+		skb = bcm570xPktAlloc (pUmDevice->index,
+				       pPacket->u.Rx.RxBufferSize + 2);
+
+		if (skb == 0) {
+			pUmPacket->skbuff = 0;
+			QQ_PushTail (&pUmDevice->rx_out_of_buf_q.Container,
+				     pPacket);
+			printf ("MM_InitializeUmPackets: out of buffer.\n");
+			continue;
+		}
+
+		pUmPacket->skbuff = skb;
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+	}
+
+	pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
+
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
+{
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	int index = pDevice->index;
+
+	if (auto_speed[index] == 0)
+		pDevice->DisableAutoNeg = TRUE;
+	else
+		pDevice->DisableAutoNeg = FALSE;
+
+	if (line_speed[index] == 0) {
+		pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
+		pDevice->DisableAutoNeg = FALSE;
+	} else {
+		if (line_speed[index] == 1000) {
+			if (pDevice->EnableTbi) {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
+			} else if (full_duplex[index]) {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
+			} else {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
+			}
+			if (!pDevice->EnableTbi)
+				pDevice->DisableAutoNeg = FALSE;
+		} else if (line_speed[index] == 100) {
+			if (full_duplex[index]) {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
+			} else {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
+			}
+		} else if (line_speed[index] == 10) {
+			if (full_duplex[index]) {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
+			} else {
+				pDevice->RequestedMediaType =
+				    LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
+			}
+		} else {
+			pDevice->RequestedMediaType =
+			    LM_REQUESTED_MEDIA_TYPE_AUTO;
+			pDevice->DisableAutoNeg = FALSE;
+		}
+
+	}
+	pDevice->FlowControlCap = 0;
+	if (rx_flow_control[index] != 0) {
+		pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
+	}
+	if (tx_flow_control[index] != 0) {
+		pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
+	}
+	if ((auto_flow_control[index] != 0) &&
+	    (pDevice->DisableAutoNeg == FALSE)) {
+
+		pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
+		if ((tx_flow_control[index] == 0) &&
+		    (rx_flow_control[index] == 0)) {
+			pDevice->FlowControlCap |=
+			    LM_FLOW_CONTROL_TRANSMIT_PAUSE |
+			    LM_FLOW_CONTROL_RECEIVE_PAUSE;
+		}
+	}
+
+	/* Default MTU for now */
+	pUmDevice->mtu = 1500;
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	if (pUmDevice->mtu > 1500) {
+		pDevice->RxMtu = pUmDevice->mtu;
+		pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
+	} else {
+		pDevice->RxJumboDescCnt = 0;
+	}
+	pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
+#else
+	pDevice->RxMtu = pUmDevice->mtu;
+#endif
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+		pDevice->UseTaggedStatus = TRUE;
+		pUmDevice->timer_interval = CFG_HZ;
+	} else {
+		pUmDevice->timer_interval = CFG_HZ / 50;
+	}
+
+	pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
+	pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
+	/* Note:  adaptive coalescence really isn't adaptive in this driver */
+	pUmDevice->rx_adaptive_coalesce = rx_adaptive_coalesce[index];
+	if (!pUmDevice->rx_adaptive_coalesce) {
+		pDevice->RxCoalescingTicks = rx_coalesce_ticks[index];
+		if (pDevice->RxCoalescingTicks > MAX_RX_COALESCING_TICKS)
+			pDevice->RxCoalescingTicks = MAX_RX_COALESCING_TICKS;
+		pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks;
+
+		pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index];
+		if (pDevice->RxMaxCoalescedFrames > MAX_RX_MAX_COALESCED_FRAMES)
+			pDevice->RxMaxCoalescedFrames =
+			    MAX_RX_MAX_COALESCED_FRAMES;
+		pUmDevice->rx_curr_coalesce_frames =
+		    pDevice->RxMaxCoalescedFrames;
+		pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
+		if (pDevice->StatsCoalescingTicks > MAX_STATS_COALESCING_TICKS)
+			pDevice->StatsCoalescingTicks =
+			    MAX_STATS_COALESCING_TICKS;
+	} else {
+		pUmDevice->rx_curr_coalesce_frames =
+		    DEFAULT_RX_MAX_COALESCED_FRAMES;
+		pUmDevice->rx_curr_coalesce_ticks = DEFAULT_RX_COALESCING_TICKS;
+	}
+	pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
+	if (pDevice->TxCoalescingTicks > MAX_TX_COALESCING_TICKS)
+		pDevice->TxCoalescingTicks = MAX_TX_COALESCING_TICKS;
+	pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
+	if (pDevice->TxMaxCoalescedFrames > MAX_TX_MAX_COALESCED_FRAMES)
+		pDevice->TxMaxCoalescedFrames = MAX_TX_MAX_COALESCED_FRAMES;
+
+	if (enable_wol[index]) {
+		pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
+		pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
+	}
+	pDevice->NicSendBd = TRUE;
+
+	/* Don't update status blocks during interrupt */
+	pDevice->RxCoalescingTicksDuringInt = 0;
+	pDevice->TxCoalescingTicksDuringInt = 0;
+
+	return LM_STATUS_SUCCESS;
+
+}
+
+LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	printf ("Start TX DMA: dev=%d packet @0x%x\n",
+		(int)pUmDevice->index, (unsigned int)pPacket);
+
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	printf ("Complete TX DMA: dev=%d packet @0x%x\n",
+		(int)pUmDevice->index, (unsigned int)pPacket);
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
+{
+	char buf[128];
+	char lcd[4];
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	LM_FLOW_CONTROL flow_control;
+
+	pUmDevice->delayed_link_ind = 0;
+	memset (lcd, 0x0, 4);
+
+	if (Status == LM_STATUS_LINK_DOWN) {
+		sprintf (buf, "eth%d: %s: NIC Link is down\n",
+			 pUmDevice->index, pUmDevice->name);
+		lcd[0] = 'L';
+		lcd[1] = 'N';
+		lcd[2] = 'K';
+		lcd[3] = '?';
+	} else if (Status == LM_STATUS_LINK_ACTIVE) {
+		sprintf (buf, "eth%d:%s: ", pUmDevice->index, pUmDevice->name);
+
+		if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) {
+			strcat (buf, "1000 Mbps ");
+			lcd[0] = '1';
+			lcd[1] = 'G';
+			lcd[2] = 'B';
+		} else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) {
+			strcat (buf, "100 Mbps ");
+			lcd[0] = '1';
+			lcd[1] = '0';
+			lcd[2] = '0';
+		} else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) {
+			strcat (buf, "10 Mbps ");
+			lcd[0] = '1';
+			lcd[1] = '0';
+			lcd[2] = ' ';
+		}
+		if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) {
+			strcat (buf, "full duplex");
+			lcd[3] = 'F';
+		} else {
+			strcat (buf, "half duplex");
+			lcd[3] = 'H';
+		}
+		strcat (buf, " link up");
+
+		flow_control = pDevice->FlowControl &
+		    (LM_FLOW_CONTROL_RECEIVE_PAUSE |
+		     LM_FLOW_CONTROL_TRANSMIT_PAUSE);
+
+		if (flow_control) {
+			if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
+				strcat (buf, ", receive ");
+				if (flow_control &
+				    LM_FLOW_CONTROL_TRANSMIT_PAUSE)
+					strcat (buf, " & transmit ");
+			} else {
+				strcat (buf, ", transmit ");
+			}
+			strcat (buf, "flow control ON");
+		} else {
+			strcat (buf, ", flow control OFF");
+		}
+		strcat (buf, "\n");
+		printf ("%s", buf);
+	}
+#if 0
+	sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
+#endif
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	PUM_PACKET pUmPacket;
+	void *skb;
+
+	pUmPacket = (PUM_PACKET) pPacket;
+
+	if ((skb = pUmPacket->skbuff))
+		bcm570xPktFree (pUmDevice->index, skb);
+
+	pUmPacket->skbuff = 0;
+
+	return LM_STATUS_SUCCESS;
+}
+
+unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
+{
+	return get_timer (0);
+}
+
+/*
+ *   Transform an MBUF chain into a single MBUF.
+ *   This routine will fail if the amount of data in the
+ *   chain overflows a transmit buffer.  In that case,
+ *   the incoming MBUF chain will be freed.  This routine can
+ *   also fail by not being able to allocate a new MBUF (including
+ *   cluster and mbuf headers).  In that case the failure is
+ *   non-fatal.  The incoming cluster chain is not freed, giving
+ *   the caller the choice of whether to try a retransmit later.
+ */
+LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+	PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	void *skbnew;
+	int len = 0;
+
+	if (len == 0)
+		return (LM_STATUS_SUCCESS);
+
+	if (len > MAX_PACKET_SIZE) {
+		printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
+			pUmDevice->index, len);
+		return (LM_STATUS_FAILURE);
+	}
+
+	skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
+
+	if (skbnew == NULL) {
+		pUmDevice->tx_full = 1;
+		printf ("eth%d: out of transmit buffers", pUmDevice->index);
+		return (LM_STATUS_FAILURE);
+	}
+
+	/* New packet values */
+	pUmPacket->skbuff = skbnew;
+	pUmPacket->lm_packet.u.Tx.FragCount = 1;
+
+	return (LM_STATUS_SUCCESS);
+}
+
+LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
+{
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	pUmDevice->rx_pkt = 1;
+	return LM_STATUS_SUCCESS;
+}
+
+LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
+{
+	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
+	PLM_PACKET pPacket;
+	PUM_PACKET pUmPacket;
+	void *skb;
+	while (TRUE) {
+
+		pPacket = (PLM_PACKET)
+		    QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
+
+		if (pPacket == 0)
+			break;
+
+		pUmPacket = (PUM_PACKET) pPacket;
+		skb = (void *)pUmPacket->skbuff;
+
+		/*
+		 * Free MBLK if we transmitted a fragmented packet or a
+		 * non-fragmented packet straight from the VxWorks
+		 * buffer pool. If packet was copied to a local transmit
+		 * buffer, then there's no MBUF to free, just free
+		 * the transmit buffer back to the cluster pool.
+		 */
+
+		if (skb)
+			bcm570xPktFree (pUmDevice->index, skb);
+
+		pUmPacket->skbuff = 0;
+		QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
+		pUmDevice->tx_pkt = 1;
+	}
+	if (pUmDevice->tx_full) {
+		if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) >=
+		    (QQ_GetSize (&pDevice->TxPacketFreeQ.Container) >> 1))
+			pUmDevice->tx_full = 0;
+	}
+	return LM_STATUS_SUCCESS;
+}
+
+/*
+ *  Scan an MBUF chain until we reach fragment number "frag"
+ *  Return its length and physical address.
+ */
+void MM_MapTxDma
+    (PLM_DEVICE_BLOCK pDevice,
+     struct _LM_PACKET *pPacket,
+     T3_64BIT_HOST_ADDR * paddr, LM_UINT32 * len, int frag) {
+	PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
+	*len = pPacket->PacketSize;
+	MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
+}
+
+/*
+ *  Convert an mbuf address, a CPU local virtual address,
+ *  to a physical address as seen from a PCI device.  Store the
+ *  result at paddr.
+ */
+void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
+		  struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
+{
+	PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
+	MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
+}
+
+void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
+{
+#if (BITS_PER_LONG == 64)
+	paddr->High = ((unsigned long)addr) >> 32;
+	paddr->Low = ((unsigned long)addr) & 0xffffffff;
+#else
+	paddr->High = 0;
+	paddr->Low = (unsigned long)addr;
+#endif
+}
+
+void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
+{
+	unsigned long baddr = (unsigned long)addr;
+#if (BITS_PER_LONG == 64)
+	set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
+#else
+	set_64bit_addr (paddr, baddr, 0);
+#endif
+}
+
+/*
+ * This combination of `inline' and `extern' has almost the effect of a
+ * macro.  The way to use it is to put a function definition in a header
+ * file with these keywords, and put another copy of the definition
+ * (lacking `inline' and `extern') in a library file.  The definition in
+ * the header file will cause most calls to the function to be inlined.
+ * If any uses of the function remain, they will refer to the single copy
+ * in the library.
+ */
+void atomic_set (atomic_t * entry, int val)
+{
+	entry->counter = val;
+}
+
+int atomic_read (atomic_t * entry)
+{
+	return entry->counter;
+}
+
+void atomic_inc (atomic_t * entry)
+{
+	if (entry)
+		entry->counter++;
+}
+
+void atomic_dec (atomic_t * entry)
+{
+	if (entry)
+		entry->counter--;
+}
+
+void atomic_sub (int a, atomic_t * entry)
+{
+	if (entry)
+		entry->counter -= a;
+}
+
+void atomic_add (int a, atomic_t * entry)
+{
+	if (entry)
+		entry->counter += a;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+void QQ_InitQueue (PQQ_CONTAINER pQueue, unsigned int QueueSize)
+{
+	pQueue->Head = 0;
+	pQueue->Tail = 0;
+	pQueue->Size = QueueSize + 1;
+	atomic_set (&pQueue->EntryCnt, 0);
+}				/* QQ_InitQueue */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+char QQ_Full (PQQ_CONTAINER pQueue)
+{
+	unsigned int NewHead;
+
+	NewHead = (pQueue->Head + 1) % pQueue->Size;
+
+	return (NewHead == pQueue->Tail);
+}				/* QQ_Full */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+char QQ_Empty (PQQ_CONTAINER pQueue)
+{
+	return (pQueue->Head == pQueue->Tail);
+}				/* QQ_Empty */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
+{
+	return pQueue->Size;
+}				/* QQ_GetSize */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
+{
+	return atomic_read (&pQueue->EntryCnt);
+}				/* QQ_GetEntryCnt */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    TRUE entry was added successfully.                                      */
+/*    FALSE queue is full.                                                    */
+/******************************************************************************/
+char QQ_PushHead (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
+{
+	unsigned int Head;
+
+	Head = (pQueue->Head + 1) % pQueue->Size;
+
+#if !defined(QQ_NO_OVERFLOW_CHECK)
+	if (Head == pQueue->Tail) {
+		return 0;
+	}			/* if */
+#endif				/* QQ_NO_OVERFLOW_CHECK */
+
+	pQueue->Array[pQueue->Head] = pEntry;
+	wmb ();
+	pQueue->Head = Head;
+	atomic_inc (&pQueue->EntryCnt);
+
+	return -1;
+}				/* QQ_PushHead */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    TRUE entry was added successfully.                                      */
+/*    FALSE queue is full.                                                    */
+/******************************************************************************/
+char QQ_PushTail (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
+{
+	unsigned int Tail;
+
+	Tail = pQueue->Tail;
+	if (Tail == 0) {
+		Tail = pQueue->Size;
+	}			/* if */
+	Tail--;
+
+#if !defined(QQ_NO_OVERFLOW_CHECK)
+	if (Tail == pQueue->Head) {
+		return 0;
+	}			/* if */
+#endif				/* QQ_NO_OVERFLOW_CHECK */
+
+	pQueue->Array[Tail] = pEntry;
+	wmb ();
+	pQueue->Tail = Tail;
+	atomic_inc (&pQueue->EntryCnt);
+
+	return -1;
+}				/* QQ_PushTail */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
+{
+	unsigned int Head;
+	PQQ_ENTRY Entry;
+
+	Head = pQueue->Head;
+
+#if !defined(QQ_NO_UNDERFLOW_CHECK)
+	if (Head == pQueue->Tail) {
+		return (PQQ_ENTRY) 0;
+	}			/* if */
+#endif				/* QQ_NO_UNDERFLOW_CHECK */
+
+	if (Head == 0) {
+		Head = pQueue->Size;
+	}			/* if */
+	Head--;
+
+	Entry = pQueue->Array[Head];
+	membar ();
+
+	pQueue->Head = Head;
+	atomic_dec (&pQueue->EntryCnt);
+
+	return Entry;
+}				/* QQ_PopHead */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
+{
+	unsigned int Tail;
+	PQQ_ENTRY Entry;
+
+	Tail = pQueue->Tail;
+
+#if !defined(QQ_NO_UNDERFLOW_CHECK)
+	if (Tail == pQueue->Head) {
+		return (PQQ_ENTRY) 0;
+	}			/* if */
+#endif				/* QQ_NO_UNDERFLOW_CHECK */
+
+	Entry = pQueue->Array[Tail];
+	membar ();
+	pQueue->Tail = (Tail + 1) % pQueue->Size;
+	atomic_dec (&pQueue->EntryCnt);
+
+	return Entry;
+}				/* QQ_PopTail */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
+{
+	if (Idx >= atomic_read (&pQueue->EntryCnt)) {
+		return (PQQ_ENTRY) 0;
+	}
+
+	if (pQueue->Head > Idx) {
+		Idx = pQueue->Head - Idx;
+	} else {
+		Idx = pQueue->Size - (Idx - pQueue->Head);
+	}
+	Idx--;
+
+	return pQueue->Array[Idx];
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
+{
+	if (Idx >= atomic_read (&pQueue->EntryCnt)) {
+		return (PQQ_ENTRY) 0;
+	}
+
+	Idx += pQueue->Tail;
+	if (Idx >= pQueue->Size) {
+		Idx = Idx - pQueue->Size;
+	}
+
+	return pQueue->Array[Idx];
+}
+
+#endif
diff --git a/drivers/net/bcm570x_autoneg.c b/drivers/net/bcm570x_autoneg.c
new file mode 100644
index 0000000..9023796
--- /dev/null
+++ b/drivers/net/bcm570x_autoneg.c
@@ -0,0 +1,439 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/******************************************************************************/
+#if !defined(CONFIG_NET_MULTI)
+#if INCLUDE_TBI_SUPPORT
+#include "bcm570x_autoneg.h"
+#include "bcm570x_mm.h"
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+void
+MM_AnTxConfig(
+    PAN_STATE_INFO pAnInfo)
+{
+    PLM_DEVICE_BLOCK pDevice;
+
+    pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
+
+    REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT);
+
+    pDevice->MacMode |= MAC_MODE_SEND_CONFIGS;
+    REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
+}
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+void
+MM_AnTxIdle(
+    PAN_STATE_INFO pAnInfo)
+{
+    PLM_DEVICE_BLOCK pDevice;
+
+    pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
+
+    pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS;
+    REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
+}
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+char
+MM_AnRxConfig(
+    PAN_STATE_INFO pAnInfo,
+    unsigned short *pRxConfig)
+{
+    PLM_DEVICE_BLOCK pDevice;
+    LM_UINT32 Value32;
+    char Retcode;
+
+    Retcode = AN_FALSE;
+
+    pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
+
+    Value32 = REG_RD(pDevice, MacCtrl.Status);
+    if(Value32 & MAC_STATUS_RECEIVING_CFG)
+    {
+	Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg);
+	*pRxConfig = (unsigned short) Value32;
+
+	Retcode = AN_TRUE;
+    }
+
+    return Retcode;
+}
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+void
+AutonegInit(
+    PAN_STATE_INFO pAnInfo)
+{
+    unsigned long j;
+
+    for(j = 0; j < sizeof(AN_STATE_INFO); j++)
+    {
+	((unsigned char *) pAnInfo)[j] = 0;
+    }
+
+    /* Initialize the default advertisement register. */
+    pAnInfo->mr_adv_full_duplex = 1;
+    pAnInfo->mr_adv_sym_pause = 1;
+    pAnInfo->mr_adv_asym_pause = 1;
+    pAnInfo->mr_an_enable = 1;
+}
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+AUTONEG_STATUS
+Autoneg8023z(
+    PAN_STATE_INFO pAnInfo)
+{
+    unsigned short RxConfig;
+    unsigned long Delta_us;
+    AUTONEG_STATUS AnRet;
+
+    /* Get the current time. */
+    if(pAnInfo->State == AN_STATE_UNKNOWN)
+    {
+	pAnInfo->RxConfig.AsUSHORT = 0;
+	pAnInfo->CurrentTime_us = 0;
+	pAnInfo->LinkTime_us = 0;
+	pAnInfo->AbilityMatchCfg = 0;
+	pAnInfo->AbilityMatchCnt = 0;
+	pAnInfo->AbilityMatch = AN_FALSE;
+	pAnInfo->IdleMatch = AN_FALSE;
+	pAnInfo->AckMatch = AN_FALSE;
+    }
+
+    /* Increment the timer tick.  This function is called every microsecon. */
+/*    pAnInfo->CurrentTime_us++; */
+
+    /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */
+    /* corresponding conditions are satisfied. */
+    if(MM_AnRxConfig(pAnInfo, &RxConfig))
+    {
+	if(RxConfig != pAnInfo->AbilityMatchCfg)
+	{
+	    pAnInfo->AbilityMatchCfg = RxConfig;
+	    pAnInfo->AbilityMatch = AN_FALSE;
+	    pAnInfo->AbilityMatchCnt = 0;
+	}
+	else
+	{
+	    pAnInfo->AbilityMatchCnt++;
+	    if(pAnInfo->AbilityMatchCnt > 1)
+	    {
+		pAnInfo->AbilityMatch = AN_TRUE;
+		pAnInfo->AbilityMatchCfg = RxConfig;
+	    }
+	}
+
+	if(RxConfig & AN_CONFIG_ACK)
+	{
+	    pAnInfo->AckMatch = AN_TRUE;
+	}
+	else
+	{
+	    pAnInfo->AckMatch = AN_FALSE;
+	}
+
+	pAnInfo->IdleMatch = AN_FALSE;
+    }
+    else
+    {
+	pAnInfo->IdleMatch = AN_TRUE;
+
+	pAnInfo->AbilityMatchCfg = 0;
+	pAnInfo->AbilityMatchCnt = 0;
+	pAnInfo->AbilityMatch = AN_FALSE;
+	pAnInfo->AckMatch = AN_FALSE;
+
+	RxConfig = 0;
+    }
+
+    /* Save the last Config. */
+    pAnInfo->RxConfig.AsUSHORT = RxConfig;
+
+    /* Default return code. */
+    AnRet = AUTONEG_STATUS_OK;
+
+    /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */
+    switch(pAnInfo->State)
+    {
+	case AN_STATE_UNKNOWN:
+	    if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an)
+	    {
+		pAnInfo->CurrentTime_us = 0;
+		pAnInfo->State = AN_STATE_AN_ENABLE;
+	    }
+
+	    /* Fall through.*/
+
+	case AN_STATE_AN_ENABLE:
+	    pAnInfo->mr_an_complete = AN_FALSE;
+	    pAnInfo->mr_page_rx = AN_FALSE;
+
+	    if(pAnInfo->mr_an_enable)
+	    {
+		pAnInfo->LinkTime_us = 0;
+		pAnInfo->AbilityMatchCfg = 0;
+		pAnInfo->AbilityMatchCnt = 0;
+		pAnInfo->AbilityMatch = AN_FALSE;
+		pAnInfo->IdleMatch = AN_FALSE;
+		pAnInfo->AckMatch = AN_FALSE;
+
+		pAnInfo->State = AN_STATE_AN_RESTART_INIT;
+	    }
+	    else
+	    {
+		pAnInfo->State = AN_STATE_DISABLE_LINK_OK;
+	    }
+	    break;
+
+	case AN_STATE_AN_RESTART_INIT:
+	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
+	    pAnInfo->mr_np_loaded = AN_FALSE;
+
+	    pAnInfo->TxConfig.AsUSHORT = 0;
+	    MM_AnTxConfig(pAnInfo);
+
+	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
+
+	    pAnInfo->State = AN_STATE_AN_RESTART;
+
+	    /* Fall through.*/
+
+	case AN_STATE_AN_RESTART:
+	    /* Get the current time and compute the delta with the saved */
+	    /* link timer. */
+	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
+	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
+	    {
+		pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT;
+	    }
+	    else
+	    {
+		AnRet = AUTONEG_STATUS_TIMER_ENABLED;
+	    }
+	    break;
+
+	case AN_STATE_DISABLE_LINK_OK:
+	    AnRet = AUTONEG_STATUS_DONE;
+	    break;
+
+	case AN_STATE_ABILITY_DETECT_INIT:
+	    /* Note: in the state diagram, this variable is set to */
+	    /* mr_adv_ability<12>.  Is this right?. */
+	    pAnInfo->mr_toggle_tx = AN_FALSE;
+
+	    /* Send the config as advertised in the advertisement register. */
+	    pAnInfo->TxConfig.AsUSHORT = 0;
+	    pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex;
+	    pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex;
+	    pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause;
+	    pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause;
+	    pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1;
+	    pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2;
+	    pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page;
+
+	    MM_AnTxConfig(pAnInfo);
+
+	    pAnInfo->State = AN_STATE_ABILITY_DETECT;
+
+	    break;
+
+	case AN_STATE_ABILITY_DETECT:
+	    if(pAnInfo->AbilityMatch == AN_TRUE &&
+		pAnInfo->RxConfig.AsUSHORT != 0)
+	    {
+		pAnInfo->State = AN_STATE_ACK_DETECT_INIT;
+	    }
+
+	    break;
+
+	case AN_STATE_ACK_DETECT_INIT:
+	    pAnInfo->TxConfig.D14_ACK = 1;
+	    MM_AnTxConfig(pAnInfo);
+
+	    pAnInfo->State = AN_STATE_ACK_DETECT;
+
+	    /* Fall through. */
+
+	case AN_STATE_ACK_DETECT:
+	    if(pAnInfo->AckMatch == AN_TRUE)
+	    {
+		if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) ==
+		    (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK))
+		{
+		    pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT;
+		}
+		else
+		{
+		    pAnInfo->State = AN_STATE_AN_ENABLE;
+		}
+	    }
+	    else if(pAnInfo->AbilityMatch == AN_TRUE &&
+		pAnInfo->RxConfig.AsUSHORT == 0)
+	    {
+		pAnInfo->State = AN_STATE_AN_ENABLE;
+	    }
+
+	    break;
+
+	case AN_STATE_COMPLETE_ACK_INIT:
+	    /* Make sure invalid bits are not set. */
+	    if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 ||
+		pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 ||
+		pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 ||
+		pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11)
+	    {
+		AnRet = AUTONEG_STATUS_FAILED;
+		break;
+	    }
+
+	    /* Set up the link partner advertisement register. */
+	    pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD;
+	    pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD;
+	    pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1;
+	    pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2;
+	    pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1;
+	    pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2;
+	    pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP;
+
+	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
+
+	    pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx;
+	    pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11;
+	    pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP;
+	    pAnInfo->mr_page_rx = AN_TRUE;
+
+	    pAnInfo->State = AN_STATE_COMPLETE_ACK;
+	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
+
+	    break;
+
+	case AN_STATE_COMPLETE_ACK:
+	    if(pAnInfo->AbilityMatch == AN_TRUE &&
+		pAnInfo->RxConfig.AsUSHORT == 0)
+	    {
+		pAnInfo->State = AN_STATE_AN_ENABLE;
+		break;
+	    }
+
+	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
+
+	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
+	    {
+		if(pAnInfo->mr_adv_next_page == 0 ||
+		    pAnInfo->mr_lp_adv_next_page == 0)
+		{
+		    pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
+		}
+		else
+		{
+		    if(pAnInfo->TxConfig.bits.D15 == 0 &&
+			pAnInfo->mr_np_rx == 0)
+		    {
+			pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
+		    }
+		    else
+		    {
+			AnRet = AUTONEG_STATUS_FAILED;
+		    }
+		}
+	    }
+
+	    break;
+
+	case AN_STATE_IDLE_DETECT_INIT:
+	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
+
+	    MM_AnTxIdle(pAnInfo);
+
+	    pAnInfo->State = AN_STATE_IDLE_DETECT;
+
+	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
+
+	    break;
+
+	case AN_STATE_IDLE_DETECT:
+	    if(pAnInfo->AbilityMatch == AN_TRUE &&
+		pAnInfo->RxConfig.AsUSHORT == 0)
+	    {
+		pAnInfo->State = AN_STATE_AN_ENABLE;
+		break;
+	    }
+
+	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
+	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
+	    {
+#if 0
+/*                if(pAnInfo->IdleMatch == AN_TRUE) */
+/*                { */
+#endif
+		    pAnInfo->State = AN_STATE_LINK_OK;
+#if 0
+/*                } */
+/*                else */
+/*                { */
+/*                    AnRet = AUTONEG_STATUS_FAILED; */
+/*                    break; */
+/*                } */
+#endif
+	    }
+
+	    break;
+
+	case AN_STATE_LINK_OK:
+	    pAnInfo->mr_an_complete = AN_TRUE;
+	    pAnInfo->mr_link_ok = AN_TRUE;
+	    AnRet = AUTONEG_STATUS_DONE;
+
+	    break;
+
+	case AN_STATE_NEXT_PAGE_WAIT_INIT:
+	    break;
+
+	case AN_STATE_NEXT_PAGE_WAIT:
+	    break;
+
+	default:
+	    AnRet = AUTONEG_STATUS_FAILED;
+	    break;
+    }
+
+    return AnRet;
+}
+#endif /* INCLUDE_TBI_SUPPORT */
+
+#endif /* !defined(CONFIG_NET_MULTI) */
diff --git a/drivers/net/bcm570x_autoneg.h b/drivers/net/bcm570x_autoneg.h
new file mode 100644
index 0000000..7830944
--- /dev/null
+++ b/drivers/net/bcm570x_autoneg.h
@@ -0,0 +1,408 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/******************************************************************************/
+
+
+#ifndef AUTONEG_H
+#define AUTONEG_H
+
+
+/******************************************************************************/
+/* Constants. */
+/******************************************************************************/
+
+#define AN_LINK_TIMER_INTERVAL_US           9000       /* 10ms */
+
+/* TRUE, FALSE */
+#define AN_TRUE                             1
+#define AN_FALSE                            0
+
+
+/******************************************************************************/
+/* Main data structure for keeping track of 802.3z auto-negotation state */
+/* variables as shown in Figure 37-6 of the IEEE 802.3z specification. */
+/******************************************************************************/
+
+typedef struct
+{
+    /* Current auto-negotiation state. */
+    unsigned long State;
+    #define AN_STATE_UNKNOWN                        0
+    #define AN_STATE_AN_ENABLE                      1
+    #define AN_STATE_AN_RESTART_INIT                2
+    #define AN_STATE_AN_RESTART                     3
+    #define AN_STATE_DISABLE_LINK_OK                4
+    #define AN_STATE_ABILITY_DETECT_INIT            5
+    #define AN_STATE_ABILITY_DETECT                 6
+    #define AN_STATE_ACK_DETECT_INIT                7
+    #define AN_STATE_ACK_DETECT                     8
+    #define AN_STATE_COMPLETE_ACK_INIT              9
+    #define AN_STATE_COMPLETE_ACK                   10
+    #define AN_STATE_IDLE_DETECT_INIT               11
+    #define AN_STATE_IDLE_DETECT                    12
+    #define AN_STATE_LINK_OK                        13
+    #define AN_STATE_NEXT_PAGE_WAIT_INIT            14
+    #define AN_STATE_NEXT_PAGE_WAIT                 16
+
+    /* Link timer. */
+    unsigned long LinkTime_us;
+
+    /* Current time. */
+    unsigned long CurrentTime_us;
+
+    /* Need these values for consistency check. */
+    unsigned short AbilityMatchCfg;
+
+    /* Ability, idle, and ack match functions. */
+    unsigned long AbilityMatchCnt;
+    char AbilityMatch;
+    char IdleMatch;
+    char AckMatch;
+
+    /* Tx config data */
+    union
+    {
+	/* The TxConfig register is arranged as follows:                      */
+	/*                                                                    */
+	/* MSB                                                           LSB  */
+	/* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+  */
+	/* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8|  */
+	/* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+  */
+	struct
+	{
+#ifdef BIG_ENDIAN_HOST
+	    unsigned int D7:1;        /* PS1 */
+	    unsigned int D6:1;        /* HD */
+	    unsigned int D5:1;        /* FD */
+	    unsigned int D4:1;
+	    unsigned int D3:1;
+	    unsigned int D2:1;
+	    unsigned int D1:1;
+	    unsigned int D0:1;
+	    unsigned int D15:1;       /* NP */
+	    unsigned int D14:1;       /* ACK */
+	    unsigned int D13:1;       /* RF2 */
+	    unsigned int D12:1;       /* RF1 */
+	    unsigned int D11:1;
+	    unsigned int D10:1;
+	    unsigned int D9:1;
+	    unsigned int D8:1;        /* PS2 */
+#else /* BIG_ENDIAN_HOST */
+	    unsigned int D8:1;        /* PS2 */
+	    unsigned int D9:1;
+	    unsigned int D10:1;
+	    unsigned int D11:1;
+	    unsigned int D12:1;       /* RF1 */
+	    unsigned int D13:1;       /* RF2 */
+	    unsigned int D14:1;       /* ACK */
+	    unsigned int D15:1;       /* NP */
+	    unsigned int D0:1;
+	    unsigned int D1:1;
+	    unsigned int D2:1;
+	    unsigned int D3:1;
+	    unsigned int D4:1;
+	    unsigned int D5:1;        /* FD */
+	    unsigned int D6:1;        /* HD */
+	    unsigned int D7:1;        /* PS1 */
+#endif
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define D8_PS2                      bits.D8
+	#define D12_RF1                     bits.D12
+	#define D13_RF2                     bits.D13
+	#define D14_ACK                     bits.D14
+	#define D15_NP                      bits.D15
+	#define D5_FD                       bits.D5
+	#define D6_HD                       bits.D6
+	#define D7_PS1                      bits.D7
+    } TxConfig;
+
+    /* Rx config data */
+    union
+    {
+	/* The RxConfig register is arranged as follows:                      */
+	/*                                                                    */
+	/* MSB                                                           LSB  */
+	/* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+  */
+	/* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8|  */
+	/* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+  */
+	struct
+	{
+#ifdef BIG_ENDIAN_HOST
+	    unsigned int D7:1;        /* PS1 */
+	    unsigned int D6:1;        /* HD */
+	    unsigned int D5:1;        /* FD */
+	    unsigned int D4:1;
+	    unsigned int D3:1;
+	    unsigned int D2:1;
+	    unsigned int D1:1;
+	    unsigned int D0:1;
+	    unsigned int D15:1;       /* NP */
+	    unsigned int D14:1;       /* ACK */
+	    unsigned int D13:1;       /* RF2 */
+	    unsigned int D12:1;       /* RF1 */
+	    unsigned int D11:1;
+	    unsigned int D10:1;
+	    unsigned int D9:1;
+	    unsigned int D8:1;        /* PS2 */
+#else /* BIG_ENDIAN_HOST */
+	    unsigned int D8:1;        /* PS2 */
+	    unsigned int D9:1;
+	    unsigned int D10:1;
+	    unsigned int D11:1;
+	    unsigned int D12:1;       /* RF1 */
+	    unsigned int D13:1;       /* RF2 */
+	    unsigned int D14:1;       /* ACK */
+	    unsigned int D15:1;       /* NP */
+	    unsigned int D0:1;
+	    unsigned int D1:1;
+	    unsigned int D2:1;
+	    unsigned int D3:1;
+	    unsigned int D4:1;
+	    unsigned int D5:1;        /* FD */
+	    unsigned int D6:1;        /* HD */
+	    unsigned int D7:1;        /* PS1 */
+#endif
+	} bits;
+
+	unsigned short AsUSHORT;
+    } RxConfig;
+
+    #define AN_CONFIG_NP                            0x0080
+    #define AN_CONFIG_ACK                           0x0040
+    #define AN_CONFIG_RF2                           0x0020
+    #define AN_CONFIG_RF1                           0x0010
+    #define AN_CONFIG_PS2                           0x0001
+    #define AN_CONFIG_PS1                           0x8000
+    #define AN_CONFIG_HD                            0x4000
+    #define AN_CONFIG_FD                            0x2000
+
+
+    /* Management registers. */
+
+    /* Control register. */
+    union
+    {
+	struct
+	{
+	    unsigned int an_enable:1;
+	    unsigned int loopback:1;
+	    unsigned int reset:1;
+	    unsigned int restart_an:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_an_enable                Mr0.bits.an_enable
+	#define mr_loopback                 Mr0.bits.loopback
+	#define mr_main_reset               Mr0.bits.reset
+	#define mr_restart_an               Mr0.bits.restart_an
+    } Mr0;
+
+    /* Status register. */
+    union
+    {
+	struct
+	{
+	    unsigned int an_complete:1;
+	    unsigned int link_ok:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_an_complete              Mr1.bits.an_complete
+	#define mr_link_ok                  Mr1.bits.link_ok
+    } Mr1;
+
+    /* Advertisement register. */
+    union
+    {
+	struct
+	{
+	    unsigned int reserved_4:5;
+	    unsigned int full_duplex:1;
+	    unsigned int half_duplex:1;
+	    unsigned int sym_pause:1;
+	    unsigned int asym_pause:1;
+	    unsigned int reserved_11:3;
+	    unsigned int remote_fault1:1;
+	    unsigned int remote_fault2:1;
+	    unsigned int reserved_14:1;
+	    unsigned int next_page:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_adv_full_duplex          Mr4.bits.full_duplex
+	#define mr_adv_half_duplex          Mr4.bits.half_duplex
+	#define mr_adv_sym_pause            Mr4.bits.sym_pause
+	#define mr_adv_asym_pause           Mr4.bits.asym_pause
+	#define mr_adv_remote_fault1        Mr4.bits.remote_fault1
+	#define mr_adv_remote_fault2        Mr4.bits.remote_fault2
+	#define mr_adv_next_page            Mr4.bits.next_page
+    } Mr4;
+
+    /* Link partner advertisement register. */
+    union
+    {
+	struct
+	{
+	    unsigned int reserved_4:5;
+	    unsigned int lp_full_duplex:1;
+	    unsigned int lp_half_duplex:1;
+	    unsigned int lp_sym_pause:1;
+	    unsigned int lp_asym_pause:1;
+	    unsigned int reserved_11:3;
+	    unsigned int lp_remote_fault1:1;
+	    unsigned int lp_remote_fault2:1;
+	    unsigned int lp_ack:1;
+	    unsigned int lp_next_page:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_lp_adv_full_duplex       Mr5.bits.lp_full_duplex
+	#define mr_lp_adv_half_duplex       Mr5.bits.lp_half_duplex
+	#define mr_lp_adv_sym_pause         Mr5.bits.lp_sym_pause
+	#define mr_lp_adv_asym_pause        Mr5.bits.lp_asym_pause
+	#define mr_lp_adv_remote_fault1     Mr5.bits.lp_remote_fault1
+	#define mr_lp_adv_remote_fault2     Mr5.bits.lp_remote_fault2
+	#define mr_lp_adv_next_page         Mr5.bits.lp_next_page
+    } Mr5;
+
+    /* Auto-negotiation expansion register. */
+    union
+    {
+	struct
+	{
+	    unsigned int reserved_0:1;
+	    unsigned int page_received:1;
+	    unsigned int next_pageable:1;
+	    unsigned int reserved_15:13;
+	} bits;
+
+	unsigned short AsUSHORT;
+    } Mr6;
+
+    /* Auto-negotiation next page transmit register. */
+    union
+    {
+	struct
+	{
+	    unsigned int code_field:11;
+	    unsigned int toggle:1;
+	    unsigned int ack2:1;
+	    unsigned int message_page:1;
+	    unsigned int reserved_14:1;
+	    unsigned int next_page:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_np_tx                    Mr7.AsUSHORT
+    } Mr7;
+
+    /* Auto-negotiation link partner ability register. */
+    union
+    {
+	struct
+	{
+	    unsigned int code_field:11;
+	    unsigned int toggle:1;
+	    unsigned int ack2:1;
+	    unsigned int message_page:1;
+	    unsigned int ack:1;
+	    unsigned int next_page:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_lp_np_rx                 Mr8.AsUSHORT
+    } Mr8;
+
+    /* Extended status register. */
+    union
+    {
+	struct
+	{
+	    unsigned int reserved_11:12;
+	    unsigned int base1000_t_hd:1;
+	    unsigned int base1000_t_fd:1;
+	    unsigned int base1000_x_hd:1;
+	    unsigned int base1000_x_fd:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+    } Mr15;
+
+    /* Miscellaneous state variables. */
+    union
+    {
+	struct
+	{
+	    unsigned int toggle_tx:1;
+	    unsigned int toggle_rx:1;
+	    unsigned int np_rx:1;
+	    unsigned int page_rx:1;
+	    unsigned int np_loaded:1;
+	} bits;
+
+	unsigned short AsUSHORT;
+
+	#define mr_toggle_tx                MrMisc.bits.toggle_tx
+	#define mr_toggle_rx                MrMisc.bits.toggle_rx
+	#define mr_np_rx                    MrMisc.bits.np_rx
+	#define mr_page_rx                  MrMisc.bits.page_rx
+	#define mr_np_loaded                MrMisc.bits.np_loaded
+    } MrMisc;
+
+
+    /* Implement specifics */
+
+    /* Pointer to the operating system specific data structure. */
+    void *pContext;
+} AN_STATE_INFO, *PAN_STATE_INFO;
+
+
+/******************************************************************************/
+/* Return code of Autoneg8023z. */
+/******************************************************************************/
+
+typedef enum
+{
+    AUTONEG_STATUS_OK               = 0,
+    AUTONEG_STATUS_DONE             = 1,
+    AUTONEG_STATUS_TIMER_ENABLED    = 2,
+    AUTONEG_STATUS_FAILED           = 0xfffffff
+} AUTONEG_STATUS, *PAUTONEG_STATUS;
+
+
+/******************************************************************************/
+/* Function prototypes. */
+/******************************************************************************/
+
+AUTONEG_STATUS Autoneg8023z(PAN_STATE_INFO pAnInfo);
+void AutonegInit(PAN_STATE_INFO pAnInfo);
+
+
+/******************************************************************************/
+/* The following functions are defined in the os-dependent module. */
+/******************************************************************************/
+
+void MM_AnTxConfig(PAN_STATE_INFO pAnInfo);
+void MM_AnTxIdle(PAN_STATE_INFO pAnInfo);
+char MM_AnRxConfig(PAN_STATE_INFO pAnInfo, unsigned short *pRxConfig);
+
+
+#endif /* AUTONEG_H */
diff --git a/drivers/net/bcm570x_bits.h b/drivers/net/bcm570x_bits.h
new file mode 100644
index 0000000..615d61e
--- /dev/null
+++ b/drivers/net/bcm570x_bits.h
@@ -0,0 +1,57 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*    02/25/00 Hav Khauv        Initial version.                              */
+/******************************************************************************/
+
+#ifndef BITS_H
+#define BITS_H
+
+
+/******************************************************************************/
+/* Bit Mask definitions */
+/******************************************************************************/
+#define BIT_NONE            0x00
+#define BIT_0               0x01
+#define BIT_1               0x02
+#define BIT_2               0x04
+#define BIT_3               0x08
+#define BIT_4               0x10
+#define BIT_5               0x20
+#define BIT_6               0x40
+#define BIT_7               0x80
+#define BIT_8               0x0100
+#define BIT_9               0x0200
+#define BIT_10              0x0400
+#define BIT_11              0x0800
+#define BIT_12              0x1000
+#define BIT_13              0x2000
+#define BIT_14              0x4000
+#define BIT_15              0x8000
+#define BIT_16              0x010000
+#define BIT_17              0x020000
+#define BIT_18              0x040000
+#define BIT_19              0x080000
+#define BIT_20              0x100000
+#define BIT_21              0x200000
+#define BIT_22              0x400000
+#define BIT_23              0x800000
+#define BIT_24              0x01000000
+#define BIT_25              0x02000000
+#define BIT_26              0x04000000
+#define BIT_27              0x08000000
+#define BIT_28              0x10000000
+#define BIT_29              0x20000000
+#define BIT_30              0x40000000
+#define BIT_31              0x80000000
+
+#endif /* BITS_H */
diff --git a/drivers/net/bcm570x_debug.h b/drivers/net/bcm570x_debug.h
new file mode 100644
index 0000000..88e209b
--- /dev/null
+++ b/drivers/net/bcm570x_debug.h
@@ -0,0 +1,109 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*    02/25/00 Hav Khauv        Initial version.                              */
+/******************************************************************************/
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+/******************************************************************************/
+/* Debug macros                                                               */
+/******************************************************************************/
+
+/* Code path for controlling output debug messages. */
+/* Define your code path here. */
+#define CP_INIT                     0x010000
+#define CP_SEND                     0x020000
+#define CP_RCV                      0x040000
+#define CP_INT                      0x080000
+#define CP_UINIT                    0x100000
+#define CP_RESET                    0x200000
+
+#define CP_ALL                      (CP_INIT | CP_SEND | CP_RCV | CP_INT | \
+				    CP_RESET | CP_UINIT)
+
+#define CP_MASK                     0xffff0000
+
+
+/* Debug message levels. */
+#define LV_VERBOSE                  0x03
+#define LV_INFORM                   0x02
+#define LV_WARN                     0x01
+#define LV_FATAL                    0x00
+
+#define LV_MASK                     0xffff
+
+
+/* Code path and messsage level combined.  These are the first argument of */
+/* the DbgMessage macro. */
+#define INIT_V                      (CP_INIT | LV_VERBOSE)
+#define INIT_I                      (CP_INIT | LV_INFORM)
+#define INIT_W                      (CP_INIT | LV_WARN)
+#define SEND_V                      (CP_SEND | LV_VERBOSE)
+#define SEND_I                      (CP_SEND | LV_INFORM)
+#define SEND_W                      (CP_SEND | LV_WARN)
+#define RCV_V                       (CP_RCV | LV_VERBOSE)
+#define RCV_I                       (CP_RCV | LV_INFORM)
+#define RCV_W                       (CP_RCV | LV_WARN)
+#define INT_V                       (CP_INT | LV_VERBOSE)
+#define INT_I                       (CP_INT | LV_INFORM)
+#define INT_W                       (CP_INT | LV_WARN)
+#define UINIT_V                     (CP_UINIT | LV_VERBOSE)
+#define UINIT_I                     (CP_UINIT | LV_INFORM)
+#define UINIT_W                     (CP_UINIT | LV_WARN)
+#define RESET_V                     (CP_RESET | LV_VERBOSE)
+#define RESET_I                     (CP_RESET | LV_INFORM)
+#define RESET_W                     (CP_RESET | LV_WARN)
+#define CPALL_V                     (CP_ALL | LV_VERBOSE)
+#define CPALL_I                     (CP_ALL | LV_INFORM)
+#define CPALL_W                     (CP_ALL | LV_WARN)
+
+
+/* All code path message levels. */
+#define FATAL                       (CP_ALL | LV_FATAL)
+#define WARN                        (CP_ALL | LV_WARN)
+#define INFORM                      (CP_ALL | LV_INFORM)
+#define VERBOSE                     (CP_ALL | LV_VERBOSE)
+
+
+/* These constants control the message output. */
+/* Set your debug message output level and code path here. */
+#ifndef DBG_MSG_CP
+#define DBG_MSG_CP                  CP_ALL      /* Where to output messages. */
+#endif
+
+#ifndef DBG_MSG_LV
+#define DBG_MSG_LV                  LV_VERBOSE  /* Level of message output. */
+#endif
+
+/* DbgMessage macro. */
+#if DBG
+#define DbgMessage(CNTRL, MESSAGE)  \
+    if((CNTRL & DBG_MSG_CP) && ((CNTRL & LV_MASK) <= DBG_MSG_LV)) \
+	printf MESSAGE
+#define DbgBreak()                 DbgBreakPoint()
+#undef STATIC
+#define STATIC
+#else
+#define DbgMessage(CNTRL, MESSAGE)
+#define DbgBreak()
+#undef STATIC
+#define STATIC static
+#endif /* DBG */
+
+
+#endif /* DEBUG_H */
diff --git a/drivers/net/bcm570x_lm.h b/drivers/net/bcm570x_lm.h
new file mode 100644
index 0000000..2ea6ca8
--- /dev/null
+++ b/drivers/net/bcm570x_lm.h
@@ -0,0 +1,434 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*    02/25/00 Hav Khauv        Initial version.                              */
+/******************************************************************************/
+
+#ifndef LM_H
+#define LM_H
+
+#include "bcm570x_queue.h"
+#include "bcm570x_bits.h"
+
+/******************************************************************************/
+/* Basic types. */
+/******************************************************************************/
+
+typedef char LM_CHAR, *PLM_CHAR;
+typedef unsigned int LM_UINT, *PLM_UINT;
+typedef unsigned char LM_UINT8, *PLM_UINT8;
+typedef unsigned short LM_UINT16, *PLM_UINT16;
+typedef unsigned int LM_UINT32, *PLM_UINT32;
+typedef unsigned int LM_COUNTER, *PLM_COUNTER;
+typedef void LM_VOID, *PLM_VOID;
+typedef char LM_BOOL, *PLM_BOOL;
+
+/* 64bit value. */
+typedef struct {
+#ifdef BIG_ENDIAN_HOST
+	LM_UINT32 High;
+	LM_UINT32 Low;
+#else				/* BIG_ENDIAN_HOST */
+	LM_UINT32 Low;
+	LM_UINT32 High;
+#endif				/* !BIG_ENDIAN_HOST */
+} LM_UINT64, *PLM_UINT64;
+
+typedef LM_UINT64 LM_PHYSICAL_ADDRESS, *PLM_PHYSICAL_ADDRESS;
+
+/* void LM_INC_PHYSICAL_ADDRESS(PLM_PHYSICAL_ADDRESS pAddr,LM_UINT32 IncSize) */
+#define LM_INC_PHYSICAL_ADDRESS(pAddr, IncSize)             \
+    {                                                       \
+	LM_UINT32 OrgLow;                                   \
+							    \
+	OrgLow = (pAddr)->Low;                              \
+	(pAddr)->Low += IncSize;                            \
+	if((pAddr)->Low < OrgLow) {                         \
+	    (pAddr)->High++; /* Wrap around. */             \
+	}                                                   \
+    }
+
+#ifndef NULL
+#define NULL                ((void *) 0)
+#endif				/* NULL */
+
+#ifndef OFFSETOF
+#define OFFSETOF(_s, _m)    (MM_UINT_PTR(&(((_s *) 0)->_m)))
+#endif				/* OFFSETOF */
+
+/******************************************************************************/
+/* Simple macros. */
+/******************************************************************************/
+
+#define IS_ETH_BROADCAST(_pEthAddr)                                         \
+    (((unsigned char *) (_pEthAddr))[0] == ((unsigned char) 0xff))
+
+#define IS_ETH_MULTICAST(_pEthAddr)                                         \
+    (((unsigned char *) (_pEthAddr))[0] & ((unsigned char) 0x01))
+
+#define IS_ETH_ADDRESS_EQUAL(_pEtherAddr1, _pEtherAddr2)                    \
+    ((((unsigned char *) (_pEtherAddr1))[0] ==                              \
+    ((unsigned char *) (_pEtherAddr2))[0]) &&                               \
+    (((unsigned char *) (_pEtherAddr1))[1] ==                               \
+    ((unsigned char *) (_pEtherAddr2))[1]) &&                               \
+    (((unsigned char *) (_pEtherAddr1))[2] ==                               \
+    ((unsigned char *) (_pEtherAddr2))[2]) &&                               \
+    (((unsigned char *) (_pEtherAddr1))[3] ==                               \
+    ((unsigned char *) (_pEtherAddr2))[3]) &&                               \
+    (((unsigned char *) (_pEtherAddr1))[4] ==                               \
+    ((unsigned char *) (_pEtherAddr2))[4]) &&                               \
+    (((unsigned char *) (_pEtherAddr1))[5] ==                               \
+    ((unsigned char *) (_pEtherAddr2))[5]))
+
+#define COPY_ETH_ADDRESS(_Src, _Dst)                                        \
+    ((unsigned char *) (_Dst))[0] = ((unsigned char *) (_Src))[0];          \
+    ((unsigned char *) (_Dst))[1] = ((unsigned char *) (_Src))[1];          \
+    ((unsigned char *) (_Dst))[2] = ((unsigned char *) (_Src))[2];          \
+    ((unsigned char *) (_Dst))[3] = ((unsigned char *) (_Src))[3];          \
+    ((unsigned char *) (_Dst))[4] = ((unsigned char *) (_Src))[4];          \
+    ((unsigned char *) (_Dst))[5] = ((unsigned char *) (_Src))[5];
+
+/******************************************************************************/
+/* Constants. */
+/******************************************************************************/
+
+#define ETHERNET_ADDRESS_SIZE           6
+#define ETHERNET_PACKET_HEADER_SIZE     14
+#define MIN_ETHERNET_PACKET_SIZE        64	/* with 4 byte crc. */
+#define MAX_ETHERNET_PACKET_SIZE        1518	/* with 4 byte crc. */
+#define MIN_ETHERNET_PACKET_SIZE_NO_CRC 60
+#define MAX_ETHERNET_PACKET_SIZE_NO_CRC 1514
+#define MAX_ETHERNET_PACKET_BUFFER_SIZE 1536	/* A nice even number. */
+
+#ifndef LM_MAX_MC_TABLE_SIZE
+#define LM_MAX_MC_TABLE_SIZE            32
+#endif				/* LM_MAX_MC_TABLE_SIZE */
+#define LM_MC_ENTRY_SIZE                (ETHERNET_ADDRESS_SIZE+1)
+#define LM_MC_INSTANCE_COUNT_INDEX      (LM_MC_ENTRY_SIZE-1)
+
+/* Receive filter masks. */
+#define LM_ACCEPT_UNICAST               0x0001
+#define LM_ACCEPT_MULTICAST             0x0002
+#define LM_ACCEPT_ALL_MULTICAST         0x0004
+#define LM_ACCEPT_BROADCAST             0x0008
+#define LM_ACCEPT_ERROR_PACKET          0x0010
+
+#define LM_PROMISCUOUS_MODE             0x10000
+
+/******************************************************************************/
+/* PCI registers. */
+/******************************************************************************/
+
+#define PCI_VENDOR_ID_REG               0x00
+#define PCI_DEVICE_ID_REG               0x02
+
+#define PCI_COMMAND_REG                 0x04
+#define PCI_IO_SPACE_ENABLE             0x0001
+#define PCI_MEM_SPACE_ENABLE            0x0002
+#define PCI_BUSMASTER_ENABLE            0x0004
+#define PCI_MEMORY_WRITE_INVALIDATE     0x0010
+#define PCI_PARITY_ERROR_ENABLE         0x0040
+#define PCI_SYSTEM_ERROR_ENABLE         0x0100
+#define PCI_FAST_BACK_TO_BACK_ENABLE    0x0200
+
+#define PCI_STATUS_REG                  0x06
+#define PCI_REV_ID_REG                  0x08
+
+#define PCI_CACHE_LINE_SIZE_REG         0x0c
+
+#define PCI_IO_BASE_ADDR_REG            0x10
+#define PCI_IO_BASE_ADDR_MASK           0xfffffff0
+
+#define PCI_MEM_BASE_ADDR_LOW           0x10
+#define PCI_MEM_BASE_ADDR_HIGH          0x14
+
+#define PCI_SUBSYSTEM_VENDOR_ID_REG     0x2c
+#define PCI_SUBSYSTEM_ID_REG            0x2e
+#define PCI_INT_LINE_REG                0x3c
+
+#define PCIX_CAP_REG                    0x40
+#define PCIX_ENABLE_RELAXED_ORDERING    BIT_17
+
+/******************************************************************************/
+/* Fragment structure. */
+/******************************************************************************/
+
+typedef struct {
+	LM_UINT32 FragSize;
+	LM_PHYSICAL_ADDRESS FragBuf;
+} LM_FRAG, *PLM_FRAG;
+
+typedef struct {
+	/* FragCount is initialized for the caller to the maximum array size, on */
+	/* return FragCount is the number of the actual fragments in the array. */
+	LM_UINT32 FragCount;
+
+	/* Total buffer size. */
+	LM_UINT32 TotalSize;
+
+	/* Fragment array buffer. */
+	LM_FRAG Fragments[1];
+} LM_FRAG_LIST, *PLM_FRAG_LIST;
+
+#define DECLARE_FRAG_LIST_BUFFER_TYPE(_FRAG_LIST_TYPE_NAME, _MAX_FRAG_COUNT) \
+    typedef struct {                                                         \
+	LM_FRAG_LIST FragList;                                               \
+	LM_FRAG FragListBuffer[_MAX_FRAG_COUNT-1];                           \
+    } _FRAG_LIST_TYPE_NAME, *P##_FRAG_LIST_TYPE_NAME
+
+/******************************************************************************/
+/* Status codes. */
+/******************************************************************************/
+
+#define LM_STATUS_SUCCESS                                       0
+#define LM_STATUS_FAILURE                                       1
+
+#define LM_STATUS_INTERRUPT_ACTIVE                              2
+#define LM_STATUS_INTERRUPT_NOT_ACTIVE                          3
+
+#define LM_STATUS_LINK_ACTIVE                                   4
+#define LM_STATUS_LINK_DOWN                                     5
+#define LM_STATUS_LINK_SETTING_MISMATCH                         6
+
+#define LM_STATUS_TOO_MANY_FRAGMENTS                            7
+#define LM_STATUS_TRANSMIT_ABORTED                              8
+#define LM_STATUS_TRANSMIT_ERROR                                9
+#define LM_STATUS_RECEIVE_ABORTED                               10
+#define LM_STATUS_RECEIVE_ERROR                                 11
+#define LM_STATUS_INVALID_PACKET_SIZE                           12
+#define LM_STATUS_OUT_OF_MAP_REGISTERS                          13
+#define LM_STATUS_UNKNOWN_ADAPTER                               14
+
+typedef LM_UINT LM_STATUS, *PLM_STATUS;
+
+/******************************************************************************/
+/* Requested media type. */
+/******************************************************************************/
+
+#define LM_REQUESTED_MEDIA_TYPE_AUTO                            0
+#define LM_REQUESTED_MEDIA_TYPE_BNC                             1
+#define LM_REQUESTED_MEDIA_TYPE_UTP_AUTO                        2
+#define LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS                      3
+#define LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX          4
+#define LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS                     5
+#define LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX         6
+#define LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS                    7
+#define LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX        8
+#define LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS                   9
+#define LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS_FULL_DUPLEX       10
+#define LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS                  11
+#define LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX      12
+#define LM_REQUESTED_MEDIA_TYPE_MAC_LOOPBACK                    0xfffe
+#define LM_REQUESTED_MEDIA_TYPE_PHY_LOOPBACK                    0xffff
+
+typedef LM_UINT32 LM_REQUESTED_MEDIA_TYPE, *PLM_REQUESTED_MEDIA_TYPE;
+
+/******************************************************************************/
+/* Media type. */
+/******************************************************************************/
+
+#define LM_MEDIA_TYPE_UNKNOWN                                   -1
+#define LM_MEDIA_TYPE_AUTO                                      0
+#define LM_MEDIA_TYPE_UTP                                       1
+#define LM_MEDIA_TYPE_BNC                                       2
+#define LM_MEDIA_TYPE_AUI                                       3
+#define LM_MEDIA_TYPE_FIBER                                     4
+
+typedef LM_UINT32 LM_MEDIA_TYPE, *PLM_MEDIA_TYPE;
+
+/******************************************************************************/
+/* Line speed. */
+/******************************************************************************/
+
+#define LM_LINE_SPEED_UNKNOWN                                   0
+#define LM_LINE_SPEED_10MBPS                                    1
+#define LM_LINE_SPEED_100MBPS                                   2
+#define LM_LINE_SPEED_1000MBPS                                  3
+
+typedef LM_UINT32 LM_LINE_SPEED, *PLM_LINE_SPEED;
+
+/******************************************************************************/
+/* Duplex mode. */
+/******************************************************************************/
+
+#define LM_DUPLEX_MODE_UNKNOWN                                  0
+#define LM_DUPLEX_MODE_HALF                                     1
+#define LM_DUPLEX_MODE_FULL                                     2
+
+typedef LM_UINT32 LM_DUPLEX_MODE, *PLM_DUPLEX_MODE;
+
+/******************************************************************************/
+/* Power state. */
+/******************************************************************************/
+
+#define LM_POWER_STATE_D0       0
+#define LM_POWER_STATE_D1       1
+#define LM_POWER_STATE_D2       2
+#define LM_POWER_STATE_D3       3
+
+typedef LM_UINT32 LM_POWER_STATE, *PLM_POWER_STATE;
+
+/******************************************************************************/
+/* Task offloading. */
+/******************************************************************************/
+
+#define LM_TASK_OFFLOAD_NONE                    0x0000
+#define LM_TASK_OFFLOAD_TX_IP_CHECKSUM          0x0001
+#define LM_TASK_OFFLOAD_RX_IP_CHECKSUM          0x0002
+#define LM_TASK_OFFLOAD_TX_TCP_CHECKSUM         0x0004
+#define LM_TASK_OFFLOAD_RX_TCP_CHECKSUM         0x0008
+#define LM_TASK_OFFLOAD_TX_UDP_CHECKSUM         0x0010
+#define LM_TASK_OFFLOAD_RX_UDP_CHECKSUM         0x0020
+#define LM_TASK_OFFLOAD_TCP_SEGMENTATION        0x0040
+
+typedef LM_UINT32 LM_TASK_OFFLOAD, *PLM_TASK_OFFLOAD;
+
+/******************************************************************************/
+/* Flow control. */
+/******************************************************************************/
+
+#define LM_FLOW_CONTROL_NONE                    0x00
+#define LM_FLOW_CONTROL_RECEIVE_PAUSE           0x01
+#define LM_FLOW_CONTROL_TRANSMIT_PAUSE          0x02
+#define LM_FLOW_CONTROL_RX_TX_PAUSE (LM_FLOW_CONTROL_RECEIVE_PAUSE | \
+    LM_FLOW_CONTROL_TRANSMIT_PAUSE)
+
+/* This value can be or-ed with RECEIVE_PAUSE and TRANSMIT_PAUSE.  If the */
+/* auto-negotiation is disabled and the RECEIVE_PAUSE and TRANSMIT_PAUSE */
+/* bits are set, then flow control is enabled regardless of link partner's */
+/* flow control capability. */
+#define LM_FLOW_CONTROL_AUTO_PAUSE              0x80000000
+
+typedef LM_UINT32 LM_FLOW_CONTROL, *PLM_FLOW_CONTROL;
+
+/******************************************************************************/
+/* Wake up mode. */
+/******************************************************************************/
+
+#define LM_WAKE_UP_MODE_NONE                    0
+#define LM_WAKE_UP_MODE_MAGIC_PACKET            1
+#define LM_WAKE_UP_MODE_NWUF                    2
+#define LM_WAKE_UP_MODE_LINK_CHANGE             4
+
+typedef LM_UINT32 LM_WAKE_UP_MODE, *PLM_WAKE_UP_MODE;
+
+/******************************************************************************/
+/* Counters. */
+/******************************************************************************/
+
+#define LM_COUNTER_FRAMES_XMITTED_OK                            0
+#define LM_COUNTER_FRAMES_RECEIVED_OK                           1
+#define LM_COUNTER_ERRORED_TRANSMIT_COUNT                       2
+#define LM_COUNTER_ERRORED_RECEIVE_COUNT                        3
+#define LM_COUNTER_RCV_CRC_ERROR                                4
+#define LM_COUNTER_ALIGNMENT_ERROR                              5
+#define LM_COUNTER_SINGLE_COLLISION_FRAMES                      6
+#define LM_COUNTER_MULTIPLE_COLLISION_FRAMES                    7
+#define LM_COUNTER_FRAMES_DEFERRED                              8
+#define LM_COUNTER_MAX_COLLISIONS                               9
+#define LM_COUNTER_RCV_OVERRUN                                  10
+#define LM_COUNTER_XMIT_UNDERRUN                                11
+#define LM_COUNTER_UNICAST_FRAMES_XMIT                          12
+#define LM_COUNTER_MULTICAST_FRAMES_XMIT                        13
+#define LM_COUNTER_BROADCAST_FRAMES_XMIT                        14
+#define LM_COUNTER_UNICAST_FRAMES_RCV                           15
+#define LM_COUNTER_MULTICAST_FRAMES_RCV                         16
+#define LM_COUNTER_BROADCAST_FRAMES_RCV                         17
+
+typedef LM_UINT32 LM_COUNTER_TYPE, *PLM_COUNTER_TYPE;
+
+/******************************************************************************/
+/* Forward definition. */
+/******************************************************************************/
+
+typedef struct _LM_DEVICE_BLOCK *PLM_DEVICE_BLOCK;
+typedef struct _LM_PACKET *PLM_PACKET;
+
+/******************************************************************************/
+/* Function prototypes. */
+/******************************************************************************/
+
+LM_STATUS LM_GetAdapterInfo (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_InitializeAdapter (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_ResetAdapter (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_DisableInterrupt (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_EnableInterrupt (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_SendPacket (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
+LM_STATUS LM_ServiceInterrupts (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_QueueRxPackets (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_SetReceiveMask (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Mask);
+LM_STATUS LM_Halt (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_Abort (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_MulticastAdd (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
+LM_STATUS LM_MulticastDel (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
+LM_STATUS LM_MulticastClear (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress);
+LM_STATUS LM_LoopbackAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pAddress);
+
+LM_UINT32 LM_GetCrcCounter (PLM_DEVICE_BLOCK pDevice);
+
+LM_WAKE_UP_MODE LM_PMCapabilities (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_NwufAdd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize,
+		      LM_UINT8 * pByteMask, LM_UINT8 * pPattern);
+LM_STATUS LM_NwufRemove (PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize,
+			 LM_UINT8 * pByteMask, LM_UINT8 * pPattern);
+LM_STATUS LM_SetPowerState (PLM_DEVICE_BLOCK pDevice,
+			    LM_POWER_STATE PowerLevel);
+
+LM_VOID LM_ReadPhy (PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg,
+		    PLM_UINT32 pData32);
+LM_VOID LM_WritePhy (PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg,
+		     LM_UINT32 Data32);
+
+LM_STATUS LM_ControlLoopBack (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Control);
+LM_STATUS LM_SetupPhy (PLM_DEVICE_BLOCK pDevice);
+int LM_BlinkLED (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDuration);
+
+/******************************************************************************/
+/* These are the OS specific functions called by LMAC. */
+/******************************************************************************/
+
+LM_STATUS MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
+			   LM_UINT16 * pValue16);
+LM_STATUS MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
+			    LM_UINT16 Value16);
+LM_STATUS MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
+			   LM_UINT32 * pValue32);
+LM_STATUS MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
+			    LM_UINT32 Value32);
+LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_MapIoBase (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
+LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
+LM_STATUS MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
+			     PLM_VOID * pMemoryBlockVirt);
+LM_STATUS MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice,
+				   LM_UINT32 BlockSize,
+				   PLM_VOID * pMemoryBlockVirt,
+				   PLM_PHYSICAL_ADDRESS pMemoryBlockPhy,
+				   LM_BOOL Cached);
+LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status);
+LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
+LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket);
+LM_STATUS LM_MbufWorkAround (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_SetLinkSpeed (PLM_DEVICE_BLOCK pDevice,
+			   LM_REQUESTED_MEDIA_TYPE RequestedMediaType);
+
+#if INCLUDE_5703_A0_FIX
+LM_STATUS LM_Load5703DmaWFirmware (PLM_DEVICE_BLOCK pDevice);
+#endif
+
+#endif				/* LM_H */
diff --git a/drivers/net/bcm570x_mm.h b/drivers/net/bcm570x_mm.h
new file mode 100644
index 0000000..ff5302f
--- /dev/null
+++ b/drivers/net/bcm570x_mm.h
@@ -0,0 +1,158 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef MM_H
+#define MM_H
+
+#define __raw_readl readl
+#define __raw_writel writel
+
+#define BIG_ENDIAN_HOST 1
+#define readl(addr) (*(volatile unsigned int*)(addr))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+/* Define memory barrier function here if needed */
+#define wmb()
+#define membar()
+#include <common.h>
+#include <asm/types.h>
+#include "bcm570x_lm.h"
+#include "bcm570x_queue.h"
+#include "tigon3.h"
+#include <pci.h>
+
+#define FALSE 0
+#define TRUE  1
+#define ERROR -1
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+extern int MM_Packet_Desc_Size;
+
+#define MM_PACKET_DESC_SIZE MM_Packet_Desc_Size
+
+DECLARE_QUEUE_TYPE (UM_RX_PACKET_Q, MAX_RX_PACKET_DESC_COUNT + 1);
+
+#define MAX_MEM 16
+
+/* Synch */
+typedef int mutex_t;
+typedef int spinlock_t;
+
+/* Embedded device control */
+typedef struct _UM_DEVICE_BLOCK {
+	LM_DEVICE_BLOCK lm_dev;
+	pci_dev_t pdev;
+	char *name;
+	void *mem_list[MAX_MEM];
+	dma_addr_t dma_list[MAX_MEM];
+	int mem_size_list[MAX_MEM];
+	int mem_list_num;
+	int mtu;
+	int index;
+	int opened;
+	int delayed_link_ind;	/* Delay link status during initial load */
+	int adapter_just_inited;	/* the first few seconds after init. */
+	int spurious_int;	/* new -- unsupported */
+	int timer_interval;
+	int adaptive_expiry;
+	int crc_counter_expiry;	/* new -- unsupported */
+	int poll_tib_expiry;	/* new -- unsupported */
+	int tx_full;
+	int tx_queued;
+	int line_speed;		/* in Mbps, 0 if link is down */
+	UM_RX_PACKET_Q rx_out_of_buf_q;
+	int rx_out_of_buf;
+	int rx_low_buf_thresh;	/* changed to rx_buf_repl_thresh */
+	int rx_buf_repl_panic_thresh;
+	int rx_buf_align;	/* new -- unsupported */
+	int do_global_lock;
+	mutex_t global_lock;
+	mutex_t undi_lock;
+	long undi_flags;
+	volatile int interrupt;
+	int tasklet_pending;
+	int tasklet_busy;	/* new -- unsupported */
+	int rx_pkt;
+	int tx_pkt;
+#ifdef NICE_SUPPORT		/* unsupported, this is a linux ioctl */
+	void (*nice_rx) (void *, void *);
+	void *nice_ctx;
+#endif				/* NICE_SUPPORT */
+	int rx_adaptive_coalesce;
+	unsigned int rx_last_cnt;
+	unsigned int tx_last_cnt;
+	unsigned int rx_curr_coalesce_frames;
+	unsigned int rx_curr_coalesce_ticks;
+	unsigned int tx_curr_coalesce_frames;	/* new -- unsupported */
+#if TIGON3_DEBUG		/* new -- unsupported */
+	uint tx_zc_count;
+	uint tx_chksum_count;
+	uint tx_himem_count;
+	uint rx_good_chksum_count;
+#endif
+	unsigned int rx_bad_chksum_count;	/* new -- unsupported */
+	unsigned int rx_misc_errors;	/* new -- unsupported */
+} UM_DEVICE_BLOCK, *PUM_DEVICE_BLOCK;
+
+/* Physical/PCI DMA address */
+typedef union {
+	dma_addr_t dma_map;
+} dma_map_t;
+
+/* Packet */
+typedef struct
+    _UM_PACKET {
+	LM_PACKET lm_packet;
+	void *skbuff;		/* Address of packet buffer */
+} UM_PACKET, *PUM_PACKET;
+
+#define MM_ACQUIRE_UNDI_LOCK(_pDevice)
+#define MM_RELEASE_UNDI_LOCK(_pDevice)
+#define MM_ACQUIRE_INT_LOCK(_pDevice)
+#define MM_RELEASE_INT_LOCK(_pDevice)
+#define MM_UINT_PTR(_ptr)   ((unsigned long) (_ptr))
+
+/* Macro for setting 64bit address struct */
+#define set_64bit_addr(paddr, low, high) \
+	(paddr)->Low = low;             \
+	(paddr)->High = high;
+
+/* Assume that PCI controller's view of host memory is same as host */
+
+#define MEM_TO_PCI_PHYS(addr) (addr)
+
+extern void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr);
+extern void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr);
+extern void MM_MapTxDma (PLM_DEVICE_BLOCK pDevice,
+			 struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr,
+			 LM_UINT32 * len, int frag);
+extern void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
+			 struct _LM_PACKET *pPacket,
+			 T3_64BIT_HOST_ADDR * paddr);
+
+/* BSP needs to provide sysUsecDelay and sysSerialPrintString */
+extern void sysSerialPrintString (char *s);
+#define MM_Wait(usec) udelay(usec)
+
+/* Define memory barrier function here if needed */
+#define wmb()
+
+#if 0
+#define cpu_to_le32(val) LONGSWAP(val)
+#endif
+#endif				/* MM_H */
diff --git a/drivers/net/bcm570x_queue.h b/drivers/net/bcm570x_queue.h
new file mode 100644
index 0000000..336b3ca
--- /dev/null
+++ b/drivers/net/bcm570x_queue.h
@@ -0,0 +1,387 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* Queue functions.                                                           */
+/*    void          QQ_InitQueue(PQQ_CONTAINER pQueue)                        */
+/*    char          QQ_Full(PQQ_CONTAINER pQueue)                             */
+/*    char          QQ_Empty(PQQ_CONTAINER pQueue)                            */
+/*    unsigned int QQ_GetSize(PQQ_CONTAINER pQueue)                          */
+/*    unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue)                      */
+/*    char          QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)       */
+/*    char          QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)       */
+/*    PQQ_ENTRY     QQ_PopHead(PQQ_CONTAINER pQueue)                          */
+/*    PQQ_ENTRY     QQ_PopTail(PQQ_CONTAINER pQueue)                          */
+/*    PQQ_ENTRY     QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx)       */
+/*    PQQ_ENTRY     QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx)       */
+/*                                                                            */
+/*                                                                            */
+/* History:                                                                   */
+/*    02/25/00 Hav Khauv        Initial version.                              */
+/******************************************************************************/
+
+#ifndef BCM_QUEUE_H
+#define BCM_QUEUE_H
+#ifndef EMBEDDED
+#define EMBEDDED 1
+#endif
+
+/******************************************************************************/
+/* Queue definitions. */
+/******************************************************************************/
+
+/* Entry for queueing. */
+typedef void *PQQ_ENTRY;
+
+/* Linux Atomic Ops support */
+typedef struct { int counter; } atomic_t;
+
+
+/*
+ * This combination of `inline' and `extern' has almost the effect of a
+ * macro.  The way to use it is to put a function definition in a header
+ * file with these keywords, and put another copy of the definition
+ * (lacking `inline' and `extern') in a library file.  The definition in
+ * the header file will cause most calls to the function to be inlined.
+ * If any uses of the function remain, they will refer to the single copy
+ * in the library.
+ */
+extern __inline void
+atomic_set(atomic_t* entry, int val)
+{
+    entry->counter = val;
+}
+extern __inline int
+atomic_read(atomic_t* entry)
+{
+    return entry->counter;
+}
+extern __inline void
+atomic_inc(atomic_t* entry)
+{
+    if(entry)
+	entry->counter++;
+}
+
+extern __inline void
+atomic_dec(atomic_t* entry)
+{
+    if(entry)
+	entry->counter--;
+}
+
+extern __inline void
+atomic_sub(int a, atomic_t* entry)
+{
+    if(entry)
+	entry->counter -= a;
+}
+extern __inline void
+atomic_add(int a, atomic_t* entry)
+{
+    if(entry)
+	entry->counter += a;
+}
+
+
+/* Queue header -- base type. */
+typedef struct {
+    unsigned int Head;
+    unsigned int Tail;
+    unsigned int Size;
+    atomic_t EntryCnt;
+    PQQ_ENTRY Array[1];
+} QQ_CONTAINER, *PQQ_CONTAINER;
+
+
+/* Declare queue type macro. */
+#define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE)            \
+								\
+    typedef struct {                                            \
+	QQ_CONTAINER Container;                                 \
+	PQQ_ENTRY EntryBuffer[_QUEUE_SIZE];                     \
+    } _QUEUE_TYPE, *P##_QUEUE_TYPE
+
+
+/******************************************************************************/
+/* Compilation switches. */
+/******************************************************************************/
+
+#if DBG
+#undef QQ_NO_OVERFLOW_CHECK
+#undef QQ_NO_UNDERFLOW_CHECK
+#endif /* DBG */
+
+#ifdef QQ_USE_MACROS
+/* notdone */
+#else
+
+#ifdef QQ_NO_INLINE
+#define __inline
+#endif /* QQ_NO_INLINE */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline void
+QQ_InitQueue(
+PQQ_CONTAINER pQueue,
+unsigned int QueueSize) {
+    pQueue->Head = 0;
+    pQueue->Tail = 0;
+    pQueue->Size = QueueSize+1;
+    atomic_set(&pQueue->EntryCnt, 0);
+} /* QQ_InitQueue */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline char
+QQ_Full(
+PQQ_CONTAINER pQueue) {
+    unsigned int NewHead;
+
+    NewHead = (pQueue->Head + 1) % pQueue->Size;
+
+    return(NewHead == pQueue->Tail);
+} /* QQ_Full */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline char
+QQ_Empty(
+PQQ_CONTAINER pQueue) {
+    return(pQueue->Head == pQueue->Tail);
+} /* QQ_Empty */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline unsigned int
+QQ_GetSize(
+PQQ_CONTAINER pQueue) {
+    return pQueue->Size;
+} /* QQ_GetSize */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline unsigned int
+QQ_GetEntryCnt(
+PQQ_CONTAINER pQueue) {
+    return atomic_read(&pQueue->EntryCnt);
+} /* QQ_GetEntryCnt */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    TRUE entry was added successfully.                                      */
+/*    FALSE queue is full.                                                    */
+/******************************************************************************/
+extern __inline char
+QQ_PushHead(
+PQQ_CONTAINER pQueue,
+PQQ_ENTRY pEntry) {
+    unsigned int Head;
+
+    Head = (pQueue->Head + 1) % pQueue->Size;
+
+#if !defined(QQ_NO_OVERFLOW_CHECK)
+    if(Head == pQueue->Tail) {
+	return 0;
+    } /* if */
+#endif /* QQ_NO_OVERFLOW_CHECK */
+
+    pQueue->Array[pQueue->Head] = pEntry;
+    wmb();
+    pQueue->Head = Head;
+    atomic_inc(&pQueue->EntryCnt);
+
+    return -1;
+} /* QQ_PushHead */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    TRUE entry was added successfully.                                      */
+/*    FALSE queue is full.                                                    */
+/******************************************************************************/
+extern __inline char
+QQ_PushTail(
+PQQ_CONTAINER pQueue,
+PQQ_ENTRY pEntry) {
+    unsigned int Tail;
+
+    Tail = pQueue->Tail;
+    if(Tail == 0) {
+	Tail = pQueue->Size;
+    } /* if */
+    Tail--;
+
+#if !defined(QQ_NO_OVERFLOW_CHECK)
+    if(Tail == pQueue->Head) {
+	return 0;
+    } /* if */
+#endif /* QQ_NO_OVERFLOW_CHECK */
+
+    pQueue->Array[Tail] = pEntry;
+    wmb();
+    pQueue->Tail = Tail;
+    atomic_inc(&pQueue->EntryCnt);
+
+    return -1;
+} /* QQ_PushTail */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline PQQ_ENTRY
+QQ_PopHead(
+PQQ_CONTAINER pQueue) {
+    unsigned int Head;
+    PQQ_ENTRY Entry;
+
+    Head = pQueue->Head;
+
+#if !defined(QQ_NO_UNDERFLOW_CHECK)
+    if(Head == pQueue->Tail) {
+	return (PQQ_ENTRY) 0;
+    } /* if */
+#endif /* QQ_NO_UNDERFLOW_CHECK */
+
+    if(Head == 0) {
+	Head = pQueue->Size;
+    } /* if */
+    Head--;
+
+    Entry = pQueue->Array[Head];
+#ifdef EMBEDDED
+    membar();
+#else
+    mb();
+#endif
+    pQueue->Head = Head;
+    atomic_dec(&pQueue->EntryCnt);
+
+    return Entry;
+} /* QQ_PopHead */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline PQQ_ENTRY
+QQ_PopTail(
+PQQ_CONTAINER pQueue) {
+    unsigned int Tail;
+    PQQ_ENTRY Entry;
+
+    Tail = pQueue->Tail;
+
+#if !defined(QQ_NO_UNDERFLOW_CHECK)
+    if(Tail == pQueue->Head) {
+	return (PQQ_ENTRY) 0;
+    } /* if */
+#endif /* QQ_NO_UNDERFLOW_CHECK */
+
+    Entry = pQueue->Array[Tail];
+#ifdef EMBEDDED
+    membar();
+#else
+    mb();
+#endif
+    pQueue->Tail = (Tail + 1) % pQueue->Size;
+    atomic_dec(&pQueue->EntryCnt);
+
+    return Entry;
+} /* QQ_PopTail */
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline PQQ_ENTRY
+QQ_GetHead(
+    PQQ_CONTAINER pQueue,
+    unsigned int Idx)
+{
+    if(Idx >= atomic_read(&pQueue->EntryCnt))
+    {
+	return (PQQ_ENTRY) 0;
+    }
+
+    if(pQueue->Head > Idx)
+    {
+	Idx = pQueue->Head - Idx;
+    }
+    else
+    {
+	Idx = pQueue->Size - (Idx - pQueue->Head);
+    }
+    Idx--;
+
+    return pQueue->Array[Idx];
+}
+
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+extern __inline PQQ_ENTRY
+QQ_GetTail(
+    PQQ_CONTAINER pQueue,
+    unsigned int Idx)
+{
+    if(Idx >= atomic_read(&pQueue->EntryCnt))
+    {
+	return (PQQ_ENTRY) 0;
+    }
+
+    Idx += pQueue->Tail;
+    if(Idx >= pQueue->Size)
+    {
+	Idx = Idx - pQueue->Size;
+    }
+
+    return pQueue->Array[Idx];
+}
+
+#endif /* QQ_USE_MACROS */
+
+
+#endif /* QUEUE_H */
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
new file mode 100644
index 0000000..80c4ba2
--- /dev/null
+++ b/drivers/net/cs8900.c
@@ -0,0 +1,322 @@
+/*
+ * Cirrus Logic CS8900A Ethernet
+ *
+ * (C) 2003 Wolfgang Denk, wd@denx.de
+ *     Extension to synchronize ethaddr environment variable
+ *     against value in EEPROM
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 1999 Ben Williamson <benw@pobox.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is loaded into SRAM in bootstrap mode, where it waits
+ * for commands on UART1 to read and write memory, jump to code etc.
+ * A design goal for this program is to be entirely independent of the
+ * target board.  Anything with a CL-PS7111 or EP7211 should be able to run
+ * this code in bootstrap mode.  All the board specifics can be handled on
+ * the host.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <command.h>
+#include "cs8900.h"
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_CS8900
+
+#if defined(CONFIG_CMD_NET)
+
+#undef DEBUG
+
+/* packet page register access functions */
+
+#ifdef CS8900_BUS32
+/* we don't need 16 bit initialisation on 32 bit bus */
+#define get_reg_init_bus(x) get_reg((x))
+#else
+static unsigned short get_reg_init_bus (int regno)
+{
+	/* force 16 bit busmode */
+	volatile unsigned char c;
+
+	c = CS8900_BUS16_0;
+	c = CS8900_BUS16_1;
+	c = CS8900_BUS16_0;
+	c = CS8900_BUS16_1;
+	c = CS8900_BUS16_0;
+
+	CS8900_PPTR = regno;
+	return (unsigned short) CS8900_PDATA;
+}
+#endif
+
+static unsigned short get_reg (int regno)
+{
+	CS8900_PPTR = regno;
+	return (unsigned short) CS8900_PDATA;
+}
+
+
+static void put_reg (int regno, unsigned short val)
+{
+	CS8900_PPTR = regno;
+	CS8900_PDATA = val;
+}
+
+static void eth_reset (void)
+{
+	int tmo;
+	unsigned short us;
+
+	/* reset NIC */
+	put_reg (PP_SelfCTL, get_reg (PP_SelfCTL) | PP_SelfCTL_Reset);
+
+	/* wait for 200ms */
+	udelay (200000);
+	/* Wait until the chip is reset */
+
+	tmo = get_timer (0) + 1 * CFG_HZ;
+	while ((((us = get_reg_init_bus (PP_SelfSTAT)) & PP_SelfSTAT_InitD) == 0)
+		   && tmo < get_timer (0))
+		/*NOP*/;
+}
+
+static void eth_reginit (void)
+{
+	/* receive only error free packets addressed to this card */
+	put_reg (PP_RxCTL, PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK);
+	/* do not generate any interrupts on receive operations */
+	put_reg (PP_RxCFG, 0);
+	/* do not generate any interrupts on transmit operations */
+	put_reg (PP_TxCFG, 0);
+	/* do not generate any interrupts on buffer operations */
+	put_reg (PP_BufCFG, 0);
+	/* enable transmitter/receiver mode */
+	put_reg (PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
+}
+
+void cs8900_get_enetaddr (uchar * addr)
+{
+	int i;
+	unsigned char env_enetaddr[6];
+	char *tmp = getenv ("ethaddr");
+	char *end;
+
+	for (i=0; i<6; i++) {
+		env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+		if (tmp)
+			tmp = (*end) ? end+1 : end;
+	}
+
+	/* verify chip id */
+	if (get_reg_init_bus (PP_ChipID) != 0x630e)
+		return;
+	eth_reset ();
+	if ((get_reg (PP_SelfST) & (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) ==
+			(PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) {
+
+		/* Load the MAC from EEPROM */
+		for (i = 0; i < 6 / 2; i++) {
+			unsigned int Addr;
+
+			Addr = get_reg (PP_IA + i * 2);
+			addr[i * 2] = Addr & 0xFF;
+			addr[i * 2 + 1] = Addr >> 8;
+		}
+
+		if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6) != 0 &&
+		    memcmp(env_enetaddr, addr, 6) != 0) {
+			printf ("\nWarning: MAC addresses don't match:\n");
+			printf ("\tHW MAC address:  "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				addr[0], addr[1],
+				addr[2], addr[3],
+				addr[4], addr[5] );
+			printf ("\t\"ethaddr\" value: "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				env_enetaddr[0], env_enetaddr[1],
+				env_enetaddr[2], env_enetaddr[3],
+				env_enetaddr[4], env_enetaddr[5]) ;
+			debug ("### Set MAC addr from environment\n");
+			memcpy (addr, env_enetaddr, 6);
+		}
+		if (!tmp) {
+			char ethaddr[20];
+			sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+				 addr[0], addr[1],
+				 addr[2], addr[3],
+				 addr[4], addr[5]) ;
+			debug ("### Set environment from HW MAC addr = \"%s\"\n",				ethaddr);
+			setenv ("ethaddr", ethaddr);
+		}
+
+	}
+}
+
+void eth_halt (void)
+{
+	/* disable transmitter/receiver mode */
+	put_reg (PP_LineCTL, 0);
+
+	/* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */
+	get_reg_init_bus (PP_ChipID);
+}
+
+int eth_init (bd_t * bd)
+{
+
+	/* verify chip id */
+	if (get_reg_init_bus (PP_ChipID) != 0x630e) {
+		printf ("CS8900 Ethernet chip not found?!\n");
+		return 0;
+	}
+
+	eth_reset ();
+	/* set the ethernet address */
+	put_reg (PP_IA + 0, bd->bi_enetaddr[0] | (bd->bi_enetaddr[1] << 8));
+	put_reg (PP_IA + 2, bd->bi_enetaddr[2] | (bd->bi_enetaddr[3] << 8));
+	put_reg (PP_IA + 4, bd->bi_enetaddr[4] | (bd->bi_enetaddr[5] << 8));
+
+	eth_reginit ();
+	return 0;
+}
+
+/* Get a data block via Ethernet */
+extern int eth_rx (void)
+{
+	int i;
+	unsigned short rxlen;
+	unsigned short *addr;
+	unsigned short status;
+
+	status = get_reg (PP_RER);
+
+	if ((status & PP_RER_RxOK) == 0)
+		return 0;
+
+	status = CS8900_RTDATA;		/* stat */
+	rxlen = CS8900_RTDATA;		/* len */
+
+#ifdef DEBUG
+	if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
+		printf ("packet too big!\n");
+#endif
+	for (addr = (unsigned short *) NetRxPackets[0], i = rxlen >> 1; i > 0;
+		 i--)
+		*addr++ = CS8900_RTDATA;
+	if (rxlen & 1)
+		*addr++ = CS8900_RTDATA;
+
+	/* Pass the packet up to the protocol layers. */
+	NetReceive (NetRxPackets[0], rxlen);
+
+	return rxlen;
+}
+
+/* Send a data block via Ethernet. */
+extern int eth_send (volatile void *packet, int length)
+{
+	volatile unsigned short *addr;
+	int tmo;
+	unsigned short s;
+
+retry:
+	/* initiate a transmit sequence */
+	CS8900_TxCMD = PP_TxCmd_TxStart_Full;
+	CS8900_TxLEN = length;
+
+	/* Test to see if the chip has allocated memory for the packet */
+	if ((get_reg (PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) {
+		/* Oops... this should not happen! */
+#ifdef DEBUG
+		printf ("cs: unable to send packet; retrying...\n");
+#endif
+		for (tmo = get_timer (0) + 5 * CFG_HZ; get_timer (0) < tmo;)
+			/*NOP*/;
+		eth_reset ();
+		eth_reginit ();
+		goto retry;
+	}
+
+	/* Write the contents of the packet */
+	/* assume even number of bytes */
+	for (addr = packet; length > 0; length -= 2)
+		CS8900_RTDATA = *addr++;
+
+	/* wait for transfer to succeed */
+	tmo = get_timer (0) + 5 * CFG_HZ;
+	while ((s = get_reg (PP_TER) & ~0x1F) == 0) {
+		if (get_timer (0) >= tmo)
+			break;
+	}
+
+	/* nothing */ ;
+	if ((s & (PP_TER_CRS | PP_TER_TxOK)) != PP_TER_TxOK) {
+#ifdef DEBUG
+		printf ("\ntransmission error %#x\n", s);
+#endif
+	}
+
+	return 0;
+}
+
+static void cs8900_e2prom_ready(void)
+{
+	while(get_reg(PP_SelfST) & SI_BUSY);
+}
+
+/***********************************************************/
+/* read a 16-bit word out of the EEPROM                    */
+/***********************************************************/
+
+int cs8900_e2prom_read(unsigned char addr, unsigned short *value)
+{
+	cs8900_e2prom_ready();
+	put_reg(PP_EECMD, EEPROM_READ_CMD | addr);
+	cs8900_e2prom_ready();
+	*value = get_reg(PP_EEData);
+
+	return 0;
+}
+
+
+/***********************************************************/
+/* write a 16-bit word into the EEPROM                     */
+/***********************************************************/
+
+int cs8900_e2prom_write(unsigned char addr, unsigned short value)
+{
+	cs8900_e2prom_ready();
+	put_reg(PP_EECMD, EEPROM_WRITE_EN);
+	cs8900_e2prom_ready();
+	put_reg(PP_EEData, value);
+	put_reg(PP_EECMD, EEPROM_WRITE_CMD | addr);
+	cs8900_e2prom_ready();
+	put_reg(PP_EECMD, EEPROM_WRITE_DIS);
+	cs8900_e2prom_ready();
+
+	return 0;
+}
+
+#endif	/* COMMANDS & CFG_NET */
+
+#endif	/* CONFIG_DRIVER_CS8900 */
diff --git a/drivers/net/cs8900.h b/drivers/net/cs8900.h
new file mode 100644
index 0000000..f886d10
--- /dev/null
+++ b/drivers/net/cs8900.h
@@ -0,0 +1,258 @@
+/*
+ * Cirrus Logic CS8900A Ethernet
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 1999 Ben Williamson <benw@pobox.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is loaded into SRAM in bootstrap mode, where it waits
+ * for commands on UART1 to read and write memory, jump to code etc.
+ * A design goal for this program is to be entirely independent of the
+ * target board.  Anything with a CL-PS7111 or EP7211 should be able to run
+ * this code in bootstrap mode.  All the board specifics can be handled on
+ * the host.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/types.h>
+#include <config.h>
+
+#ifdef CONFIG_DRIVER_CS8900
+
+/* although the registers are 16 bit, they are 32-bit aligned on the
+   EDB7111. so we have to read them as 32-bit registers and ignore the
+   upper 16-bits. i'm not sure if this holds for the EDB7211. */
+
+#ifdef CS8900_BUS16
+  /* 16 bit aligned registers, 16 bit wide */
+  #define CS8900_REG u16
+  #define CS8900_OFF 0x02
+  #define CS8900_BUS16_0  *(volatile u8 *)(CS8900_BASE+0x00)
+  #define CS8900_BUS16_1  *(volatile u8 *)(CS8900_BASE+0x01)
+#elif  defined(CS8900_BUS32)
+  /* 32 bit aligned registers, 16 bit wide (we ignore upper 16 bits) */
+  #define CS8900_REG u32
+  #define CS8900_OFF 0x04
+#else
+  #error unknown bussize ...
+#endif
+
+#define CS8900_RTDATA *(volatile CS8900_REG *)(CS8900_BASE+0x00*CS8900_OFF)
+#define CS8900_TxCMD  *(volatile CS8900_REG *)(CS8900_BASE+0x02*CS8900_OFF)
+#define CS8900_TxLEN  *(volatile CS8900_REG *)(CS8900_BASE+0x03*CS8900_OFF)
+#define CS8900_ISQ    *(volatile CS8900_REG *)(CS8900_BASE+0x04*CS8900_OFF)
+#define CS8900_PPTR   *(volatile CS8900_REG *)(CS8900_BASE+0x05*CS8900_OFF)
+#define CS8900_PDATA  *(volatile CS8900_REG *)(CS8900_BASE+0x06*CS8900_OFF)
+
+
+#define ISQ_RxEvent     0x04
+#define ISQ_TxEvent     0x08
+#define ISQ_BufEvent    0x0C
+#define ISQ_RxMissEvent 0x10
+#define ISQ_TxColEvent  0x12
+#define ISQ_EventMask   0x3F
+
+/* packet page register offsets */
+
+/* bus interface registers */
+#define PP_ChipID    0x0000  /* Chip identifier - must be 0x630E */
+#define PP_ChipRev   0x0002  /* Chip revision, model codes */
+
+#define PP_IntReg    0x0022  /* Interrupt configuration */
+#define PP_IntReg_IRQ0         0x0000  /* Use INTR0 pin */
+#define PP_IntReg_IRQ1         0x0001  /* Use INTR1 pin */
+#define PP_IntReg_IRQ2         0x0002  /* Use INTR2 pin */
+#define PP_IntReg_IRQ3         0x0003  /* Use INTR3 pin */
+
+/* status and control registers */
+
+#define PP_RxCFG     0x0102  /* Receiver configuration */
+#define PP_RxCFG_Skip1         0x0040  /* Skip (i.e. discard) current frame */
+#define PP_RxCFG_Stream        0x0080  /* Enable streaming mode */
+#define PP_RxCFG_RxOK          0x0100  /* RxOK interrupt enable */
+#define PP_RxCFG_RxDMAonly     0x0200  /* Use RxDMA for all frames */
+#define PP_RxCFG_AutoRxDMA     0x0400  /* Select RxDMA automatically */
+#define PP_RxCFG_BufferCRC     0x0800  /* Include CRC characters in frame */
+#define PP_RxCFG_CRC           0x1000  /* Enable interrupt on CRC error */
+#define PP_RxCFG_RUNT          0x2000  /* Enable interrupt on RUNT frames */
+#define PP_RxCFG_EXTRA         0x4000  /* Enable interrupt on frames with extra data */
+
+#define PP_RxCTL     0x0104  /* Receiver control */
+#define PP_RxCTL_IAHash        0x0040  /* Accept frames that match hash */
+#define PP_RxCTL_Promiscuous   0x0080  /* Accept any frame */
+#define PP_RxCTL_RxOK          0x0100  /* Accept well formed frames */
+#define PP_RxCTL_Multicast     0x0200  /* Accept multicast frames */
+#define PP_RxCTL_IA            0x0400  /* Accept frame that matches IA */
+#define PP_RxCTL_Broadcast     0x0800  /* Accept broadcast frames */
+#define PP_RxCTL_CRC           0x1000  /* Accept frames with bad CRC */
+#define PP_RxCTL_RUNT          0x2000  /* Accept runt frames */
+#define PP_RxCTL_EXTRA         0x4000  /* Accept frames that are too long */
+
+#define PP_TxCFG     0x0106  /* Transmit configuration */
+#define PP_TxCFG_CRS           0x0040  /* Enable interrupt on loss of carrier */
+#define PP_TxCFG_SQE           0x0080  /* Enable interrupt on Signal Quality Error */
+#define PP_TxCFG_TxOK          0x0100  /* Enable interrupt on successful xmits */
+#define PP_TxCFG_Late          0x0200  /* Enable interrupt on "out of window" */
+#define PP_TxCFG_Jabber        0x0400  /* Enable interrupt on jabber detect */
+#define PP_TxCFG_Collision     0x0800  /* Enable interrupt if collision */
+#define PP_TxCFG_16Collisions  0x8000  /* Enable interrupt if > 16 collisions */
+
+#define PP_TxCmd     0x0108  /* Transmit command status */
+#define PP_TxCmd_TxStart_5     0x0000  /* Start after 5 bytes in buffer */
+#define PP_TxCmd_TxStart_381   0x0040  /* Start after 381 bytes in buffer */
+#define PP_TxCmd_TxStart_1021  0x0080  /* Start after 1021 bytes in buffer */
+#define PP_TxCmd_TxStart_Full  0x00C0  /* Start after all bytes loaded */
+#define PP_TxCmd_Force         0x0100  /* Discard any pending packets */
+#define PP_TxCmd_OneCollision  0x0200  /* Abort after a single collision */
+#define PP_TxCmd_NoCRC         0x1000  /* Do not add CRC */
+#define PP_TxCmd_NoPad         0x2000  /* Do not pad short packets */
+
+#define PP_BufCFG    0x010A  /* Buffer configuration */
+#define PP_BufCFG_SWI          0x0040  /* Force interrupt via software */
+#define PP_BufCFG_RxDMA        0x0080  /* Enable interrupt on Rx DMA */
+#define PP_BufCFG_TxRDY        0x0100  /* Enable interrupt when ready for Tx */
+#define PP_BufCFG_TxUE         0x0200  /* Enable interrupt in Tx underrun */
+#define PP_BufCFG_RxMiss       0x0400  /* Enable interrupt on missed Rx packets */
+#define PP_BufCFG_Rx128        0x0800  /* Enable Rx interrupt after 128 bytes */
+#define PP_BufCFG_TxCol        0x1000  /* Enable int on Tx collision ctr overflow */
+#define PP_BufCFG_Miss         0x2000  /* Enable int on Rx miss ctr overflow */
+#define PP_BufCFG_RxDest       0x8000  /* Enable int on Rx dest addr match */
+
+#define PP_LineCTL   0x0112  /* Line control */
+#define PP_LineCTL_Rx          0x0040  /* Enable receiver */
+#define PP_LineCTL_Tx          0x0080  /* Enable transmitter */
+#define PP_LineCTL_AUIonly     0x0100  /* AUI interface only */
+#define PP_LineCTL_AutoAUI10BT 0x0200  /* Autodetect AUI or 10BaseT interface */
+#define PP_LineCTL_ModBackoffE 0x0800  /* Enable modified backoff algorithm */
+#define PP_LineCTL_PolarityDis 0x1000  /* Disable Rx polarity autodetect */
+#define PP_LineCTL_2partDefDis 0x2000  /* Disable two-part defferal */
+#define PP_LineCTL_LoRxSquelch 0x4000  /* Reduce receiver squelch threshold */
+
+#define PP_SelfCTL   0x0114  /* Chip self control */
+#define PP_SelfCTL_Reset       0x0040  /* Self-clearing reset */
+#define PP_SelfCTL_SWSuspend   0x0100  /* Initiate suspend mode */
+#define PP_SelfCTL_HWSleepE    0x0200  /* Enable SLEEP input */
+#define PP_SelfCTL_HWStandbyE  0x0400  /* Enable standby mode */
+#define PP_SelfCTL_HC0E        0x1000  /* use HCB0 for LINK LED */
+#define PP_SelfCTL_HC1E        0x2000  /* use HCB1 for BSTATUS LED */
+#define PP_SelfCTL_HCB0        0x4000  /* control LINK LED if HC0E set */
+#define PP_SelfCTL_HCB1        0x8000  /* control BSTATUS LED if HC1E set */
+
+#define PP_BusCTL    0x0116  /* Bus control */
+#define PP_BusCTL_ResetRxDMA   0x0040  /* Reset RxDMA pointer */
+#define PP_BusCTL_DMAextend    0x0100  /* Extend DMA cycle */
+#define PP_BusCTL_UseSA        0x0200  /* Assert MEMCS16 on address decode */
+#define PP_BusCTL_MemoryE      0x0400  /* Enable memory mode */
+#define PP_BusCTL_DMAburst     0x0800  /* Limit DMA access burst */
+#define PP_BusCTL_IOCHRDYE     0x1000  /* Set IOCHRDY high impedence */
+#define PP_BusCTL_RxDMAsize    0x2000  /* Set DMA buffer size 64KB */
+#define PP_BusCTL_EnableIRQ    0x8000  /* Generate interrupt on interrupt event */
+
+#define PP_TestCTL   0x0118  /* Test control */
+#define PP_TestCTL_DisableLT   0x0080  /* Disable link status */
+#define PP_TestCTL_ENDECloop   0x0200  /* Internal loopback */
+#define PP_TestCTL_AUIloop     0x0400  /* AUI loopback */
+#define PP_TestCTL_DisBackoff  0x0800  /* Disable backoff algorithm */
+#define PP_TestCTL_FDX         0x4000  /* Enable full duplex mode */
+
+#define PP_ISQ       0x0120  /* Interrupt Status Queue */
+
+#define PP_RER       0x0124  /* Receive event */
+#define PP_RER_IAHash          0x0040  /* Frame hash match */
+#define PP_RER_Dribble         0x0080  /* Frame had 1-7 extra bits after last byte */
+#define PP_RER_RxOK            0x0100  /* Frame received with no errors */
+#define PP_RER_Hashed          0x0200  /* Frame address hashed OK */
+#define PP_RER_IA              0x0400  /* Frame address matched IA */
+#define PP_RER_Broadcast       0x0800  /* Broadcast frame */
+#define PP_RER_CRC             0x1000  /* Frame had CRC error */
+#define PP_RER_RUNT            0x2000  /* Runt frame */
+#define PP_RER_EXTRA           0x4000  /* Frame was too long */
+
+#define PP_TER       0x0128 /* Transmit event */
+#define PP_TER_CRS             0x0040  /* Carrier lost */
+#define PP_TER_SQE             0x0080  /* Signal Quality Error */
+#define PP_TER_TxOK            0x0100  /* Packet sent without error */
+#define PP_TER_Late            0x0200  /* Out of window */
+#define PP_TER_Jabber          0x0400  /* Stuck transmit? */
+#define PP_TER_NumCollisions   0x7800  /* Number of collisions */
+#define PP_TER_16Collisions    0x8000  /* > 16 collisions */
+
+#define PP_BER       0x012C /* Buffer event */
+#define PP_BER_SWint           0x0040 /* Software interrupt */
+#define PP_BER_RxDMAFrame      0x0080 /* Received framed DMAed */
+#define PP_BER_Rdy4Tx          0x0100 /* Ready for transmission */
+#define PP_BER_TxUnderrun      0x0200 /* Transmit underrun */
+#define PP_BER_RxMiss          0x0400 /* Received frame missed */
+#define PP_BER_Rx128           0x0800 /* 128 bytes received */
+#define PP_BER_RxDest          0x8000 /* Received framed passed address filter */
+
+#define PP_RxMiss    0x0130  /*  Receiver miss counter */
+
+#define PP_TxCol     0x0132  /*  Transmit collision counter */
+
+#define PP_LineSTAT  0x0134  /* Line status */
+#define PP_LineSTAT_LinkOK     0x0080  /* Line is connected and working */
+#define PP_LineSTAT_AUI        0x0100  /* Connected via AUI */
+#define PP_LineSTAT_10BT       0x0200  /* Connected via twisted pair */
+#define PP_LineSTAT_Polarity   0x1000  /* Line polarity OK (10BT only) */
+#define PP_LineSTAT_CRS        0x4000  /* Frame being received */
+
+#define PP_SelfSTAT  0x0136  /* Chip self status */
+#define PP_SelfSTAT_33VActive  0x0040  /* supply voltage is 3.3V */
+#define PP_SelfSTAT_InitD      0x0080  /* Chip initialization complete */
+#define PP_SelfSTAT_SIBSY      0x0100  /* EEPROM is busy */
+#define PP_SelfSTAT_EEPROM     0x0200  /* EEPROM present */
+#define PP_SelfSTAT_EEPROM_OK  0x0400  /* EEPROM checks out */
+#define PP_SelfSTAT_ELPresent  0x0800  /* External address latch logic available */
+#define PP_SelfSTAT_EEsize     0x1000  /* Size of EEPROM */
+
+#define PP_BusSTAT   0x0138  /* Bus status */
+#define PP_BusSTAT_TxBid       0x0080  /* Tx error */
+#define PP_BusSTAT_TxRDY       0x0100  /* Ready for Tx data */
+
+#define PP_TDR       0x013C  /* AUI Time Domain Reflectometer */
+
+/* initiate transmit registers */
+
+#define PP_TxCommand 0x0144  /* Tx Command */
+#define PP_TxLength  0x0146  /* Tx Length */
+
+
+/* address filter registers */
+
+#define PP_LAF       0x0150  /* Logical address filter (6 bytes) */
+#define PP_IA        0x0158  /* Individual address (MAC) */
+
+/* EEPROM Kram */
+#define SI_BUSY 0x0100
+#define PP_SelfST 0x0136	/*  Self State register */
+#define PP_EECMD 0x0040		/*  NVR Interface Command register */
+#define PP_EEData 0x0042	/*  NVR Interface Data Register */
+#define EEPROM_WRITE_EN		0x00F0
+#define EEPROM_WRITE_DIS	0x0000
+#define EEPROM_WRITE_CMD	0x0100
+#define EEPROM_READ_CMD		0x0200
+#define EEPROM_ERASE_CMD	0x0300
+
+extern int cs8900_e2prom_read(uchar, ushort *);
+extern int cs8900_e2prom_write(uchar, ushort);
+
+#endif /* CONFIG_DRIVER_CS8900 */
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
new file mode 100644
index 0000000..d5275dc
--- /dev/null
+++ b/drivers/net/dc2114x.c
@@ -0,0 +1,771 @@
+/*
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_TULIP)
+
+#include <malloc.h>
+#include <net.h>
+#include <pci.h>
+
+#undef DEBUG_SROM
+#undef DEBUG_SROM2
+
+#undef UPDATE_SROM
+
+/* PCI Registers.
+ */
+#define PCI_CFDA_PSM		0x43
+
+#define CFRV_RN		0x000000f0	/* Revision Number */
+
+#define WAKEUP		0x00		/* Power Saving Wakeup */
+#define SLEEP		0x80		/* Power Saving Sleep Mode */
+
+#define DC2114x_BRK	0x0020		/* CFRV break between DC21142 & DC21143 */
+
+/* Ethernet chip registers.
+ */
+#define DE4X5_BMR	0x000		/* Bus Mode Register */
+#define DE4X5_TPD	0x008		/* Transmit Poll Demand Reg */
+#define DE4X5_RRBA	0x018		/* RX Ring Base Address Reg */
+#define DE4X5_TRBA	0x020		/* TX Ring Base Address Reg */
+#define DE4X5_STS	0x028		/* Status Register */
+#define DE4X5_OMR	0x030		/* Operation Mode Register */
+#define DE4X5_SICR	0x068		/* SIA Connectivity Register */
+#define DE4X5_APROM	0x048		/* Ethernet Address PROM */
+
+/* Register bits.
+ */
+#define BMR_SWR		0x00000001	/* Software Reset */
+#define STS_TS		0x00700000	/* Transmit Process State */
+#define STS_RS		0x000e0000	/* Receive Process State */
+#define OMR_ST		0x00002000	/* Start/Stop Transmission Command */
+#define OMR_SR		0x00000002	/* Start/Stop Receive */
+#define OMR_PS		0x00040000	/* Port Select */
+#define OMR_SDP		0x02000000	/* SD Polarity - MUST BE ASSERTED */
+#define OMR_PM		0x00000080	/* Pass All Multicast */
+
+/* Descriptor bits.
+ */
+#define R_OWN		0x80000000	/* Own Bit */
+#define RD_RER		0x02000000	/* Receive End Of Ring */
+#define RD_LS		0x00000100	/* Last Descriptor */
+#define RD_ES		0x00008000	/* Error Summary */
+#define TD_TER		0x02000000	/* Transmit End Of Ring */
+#define T_OWN		0x80000000	/* Own Bit */
+#define TD_LS		0x40000000	/* Last Segment */
+#define TD_FS		0x20000000	/* First Segment */
+#define TD_ES		0x00008000	/* Error Summary */
+#define TD_SET		0x08000000	/* Setup Packet */
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define SROM_WRITE_CMD	5
+#define SROM_READ_CMD	6
+#define SROM_ERASE_CMD	7
+
+#define SROM_HWADD	    0x0014	/* Hardware Address offset in SROM */
+#define SROM_RD		0x00004000	/* Read from Boot ROM */
+#define EE_DATA_WRITE	      0x04	/* EEPROM chip data in. */
+#define EE_WRITE_0	    0x4801
+#define EE_WRITE_1	    0x4805
+#define EE_DATA_READ	      0x08	/* EEPROM chip data out. */
+#define SROM_SR		0x00000800	/* Select Serial ROM when set */
+
+#define DT_IN		0x00000004	/* Serial Data In */
+#define DT_CLK		0x00000002	/* Serial ROM Clock */
+#define DT_CS		0x00000001	/* Serial ROM Chip Select */
+
+#define POLL_DEMAND	1
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+#define RESET_DM9102(dev) {\
+    unsigned long i;\
+    i=INL(dev, 0x0);\
+    udelay(1000);\
+    OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
+    udelay(1000);\
+}
+#else
+#define RESET_DE4X5(dev) {\
+    int i;\
+    i=INL(dev, DE4X5_BMR);\
+    udelay(1000);\
+    OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
+    udelay(1000);\
+    OUTL(dev, i, DE4X5_BMR);\
+    udelay(1000);\
+    for (i=0;i<5;i++) {INL(dev, DE4X5_BMR); udelay(10000);}\
+    udelay(1000);\
+}
+#endif
+
+#define START_DE4X5(dev) {\
+    s32 omr; \
+    omr = INL(dev, DE4X5_OMR);\
+    omr |= OMR_ST | OMR_SR;\
+    OUTL(dev, omr, DE4X5_OMR);		/* Enable the TX and/or RX */\
+}
+
+#define STOP_DE4X5(dev) {\
+    s32 omr; \
+    omr = INL(dev, DE4X5_OMR);\
+    omr &= ~(OMR_ST|OMR_SR);\
+    OUTL(dev, omr, DE4X5_OMR);		/* Disable the TX and/or RX */ \
+}
+
+#define NUM_RX_DESC PKTBUFSRX
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+	#define NUM_TX_DESC 1			/* Number of TX descriptors   */
+#else
+	#define NUM_TX_DESC 4
+#endif
+#define RX_BUFF_SZ  PKTSIZE_ALIGN
+
+#define TOUT_LOOP   1000000
+
+#define SETUP_FRAME_LEN 192
+#define ETH_ALEN	6
+
+struct de4x5_desc {
+	volatile s32 status;
+	u32 des1;
+	u32 buf;
+	u32 next;
+};
+
+static struct de4x5_desc rx_ring[NUM_RX_DESC] __attribute__ ((aligned(32))); /* RX descriptor ring         */
+static struct de4x5_desc tx_ring[NUM_TX_DESC] __attribute__ ((aligned(32))); /* TX descriptor ring         */
+static int rx_new;                             /* RX descriptor ring pointer */
+static int tx_new;                             /* TX descriptor ring pointer */
+
+static char rxRingSize;
+static char txRingSize;
+
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+static void  sendto_srom(struct eth_device* dev, u_int command, u_long addr);
+static int   getfrom_srom(struct eth_device* dev, u_long addr);
+static int   do_eeprom_cmd(struct eth_device *dev, u_long ioaddr,int cmd,int cmd_len);
+static int   do_read_eeprom(struct eth_device *dev,u_long ioaddr,int location,int addr_len);
+#endif	/* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+#ifdef UPDATE_SROM
+static int   write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value);
+static void  update_srom(struct eth_device *dev, bd_t *bis);
+#endif
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static int   read_srom(struct eth_device *dev, u_long ioaddr, int index);
+static void  read_hw_addr(struct eth_device* dev, bd_t * bis);
+#endif	/* CONFIG_TULIP_FIX_DAVICOM */
+static void  send_setup_frame(struct eth_device* dev, bd_t * bis);
+
+static int   dc21x4x_init(struct eth_device* dev, bd_t* bis);
+static int   dc21x4x_send(struct eth_device* dev, volatile void *packet, int length);
+static int   dc21x4x_recv(struct eth_device* dev);
+static void  dc21x4x_halt(struct eth_device* dev);
+#ifdef CONFIG_TULIP_SELECT_MEDIA
+extern void  dc21x4x_select_media(struct eth_device* dev);
+#endif
+
+#if defined(CONFIG_E500)
+#define phys_to_bus(a) (a)
+#else
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+#endif
+
+static int INL(struct eth_device* dev, u_long addr)
+{
+	return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase));
+}
+
+static void OUTL(struct eth_device* dev, int command, u_long addr)
+{
+	*(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command);
+}
+
+static struct pci_device_id supported[] = {
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+	{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DAVICOM_DM9102A },
+#endif
+	{ }
+};
+
+int dc21x4x_initialize(bd_t *bis)
+{
+	int             	idx=0;
+	int             	card_number = 0;
+	unsigned int           	cfrv;
+	unsigned char   	timer;
+	pci_dev_t		devbusfn;
+	unsigned int		iobase;
+	unsigned short		status;
+	struct eth_device* 	dev;
+
+	while(1) {
+		devbusfn =  pci_find_devices(supported, idx++);
+		if (devbusfn == -1) {
+			break;
+		}
+
+		/* Get the chip configuration revision register. */
+		pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+		if ((cfrv & CFRV_RN) < DC2114x_BRK ) {
+			printf("Error: The chip is not DC21143.\n");
+			continue;
+		}
+#endif
+
+		pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+		status |=
+#ifdef CONFIG_TULIP_USE_IO
+		  PCI_COMMAND_IO |
+#else
+		  PCI_COMMAND_MEMORY |
+#endif
+		  PCI_COMMAND_MASTER;
+		pci_write_config_word(devbusfn, PCI_COMMAND, status);
+
+		pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+		if (!(status & PCI_COMMAND_IO)) {
+			printf("Error: Can not enable I/O access.\n");
+			continue;
+		}
+
+		if (!(status & PCI_COMMAND_IO)) {
+			printf("Error: Can not enable I/O access.\n");
+			continue;
+		}
+
+		if (!(status & PCI_COMMAND_MASTER)) {
+			printf("Error: Can not enable Bus Mastering.\n");
+			continue;
+		}
+
+		/* Check the latency timer for values >= 0x60. */
+		pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
+
+		if (timer < 0x60) {
+			pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x60);
+		}
+
+#ifdef CONFIG_TULIP_USE_IO
+		/* read BAR for memory space access */
+		pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &iobase);
+		iobase &= PCI_BASE_ADDRESS_IO_MASK;
+#else
+		/* read BAR for memory space access */
+		pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
+		iobase &= PCI_BASE_ADDRESS_MEM_MASK;
+#endif
+		debug ("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
+
+		dev = (struct eth_device*) malloc(sizeof *dev);
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+		sprintf(dev->name, "Davicom#%d", card_number);
+#else
+		sprintf(dev->name, "dc21x4x#%d", card_number);
+#endif
+
+#ifdef CONFIG_TULIP_USE_IO
+		dev->iobase = pci_io_to_phys(devbusfn, iobase);
+#else
+		dev->iobase = pci_mem_to_phys(devbusfn, iobase);
+#endif
+		dev->priv   = (void*) devbusfn;
+		dev->init   = dc21x4x_init;
+		dev->halt   = dc21x4x_halt;
+		dev->send   = dc21x4x_send;
+		dev->recv   = dc21x4x_recv;
+
+		/* Ensure we're not sleeping. */
+		pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+		udelay(10 * 1000);
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+		read_hw_addr(dev, bis);
+#endif
+		eth_register(dev);
+
+		card_number++;
+	}
+
+	return card_number;
+}
+
+static int dc21x4x_init(struct eth_device* dev, bd_t* bis)
+{
+	int		i;
+	int		devbusfn = (int) dev->priv;
+
+	/* Ensure we're not sleeping. */
+	pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+	RESET_DM9102(dev);
+#else
+	RESET_DE4X5(dev);
+#endif
+
+	if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
+		printf("Error: Cannot reset ethernet controller.\n");
+		return 0;
+	}
+
+#ifdef CONFIG_TULIP_SELECT_MEDIA
+	dc21x4x_select_media(dev);
+#else
+	OUTL(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
+#endif
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		rx_ring[i].status = cpu_to_le32(R_OWN);
+		rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+		rx_ring[i].buf = cpu_to_le32(phys_to_bus((u32) NetRxPackets[i]));
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+		rx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &rx_ring[(i+1) % NUM_RX_DESC]));
+#else
+		rx_ring[i].next = 0;
+#endif
+	}
+
+	for (i=0; i < NUM_TX_DESC; i++) {
+		tx_ring[i].status = 0;
+		tx_ring[i].des1 = 0;
+		tx_ring[i].buf = 0;
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+	tx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &tx_ring[(i+1) % NUM_TX_DESC]));
+#else
+		tx_ring[i].next = 0;
+#endif
+	}
+
+	rxRingSize = NUM_RX_DESC;
+	txRingSize = NUM_TX_DESC;
+
+	/* Write the end of list marker to the descriptor lists. */
+	rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
+	tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
+
+	/* Tell the adapter where the TX/RX rings are located. */
+	OUTL(dev, phys_to_bus((u32) &rx_ring), DE4X5_RRBA);
+	OUTL(dev, phys_to_bus((u32) &tx_ring), DE4X5_TRBA);
+
+	START_DE4X5(dev);
+
+	tx_new = 0;
+	rx_new = 0;
+
+	send_setup_frame(dev, bis);
+
+	return 1;
+}
+
+static int dc21x4x_send(struct eth_device* dev, volatile void *packet, int length)
+{
+	int		status = -1;
+	int		i;
+
+	if (length <= 0) {
+		printf("%s: bad packet size: %d\n", dev->name, length);
+		goto Done;
+	}
+
+	for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+		if (i >= TOUT_LOOP) {
+			printf("%s: tx error buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	tx_ring[tx_new].buf    = cpu_to_le32(phys_to_bus((u32) packet));
+	tx_ring[tx_new].des1   = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
+	tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+	OUTL(dev, POLL_DEMAND, DE4X5_TPD);
+
+	for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+		if (i >= TOUT_LOOP) {
+			printf(".%s: tx buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) {
+#if 0 /* test-only */
+		printf("TX error status = 0x%08X\n",
+			le32_to_cpu(tx_ring[tx_new].status));
+#endif
+		tx_ring[tx_new].status = 0x0;
+		goto Done;
+	}
+
+	status = length;
+
+ Done:
+    tx_new = (tx_new+1) % NUM_TX_DESC;
+	return status;
+}
+
+static int dc21x4x_recv(struct eth_device* dev)
+{
+	s32		status;
+	int		length    = 0;
+
+	for ( ; ; ) {
+		status = (s32)le32_to_cpu(rx_ring[rx_new].status);
+
+		if (status & R_OWN) {
+			break;
+		}
+
+		if (status & RD_LS) {
+			/* Valid frame status.
+			 */
+			if (status & RD_ES) {
+
+				/* There was an error.
+				 */
+				printf("RX error status = 0x%08X\n", status);
+			} else {
+				/* A valid frame received.
+				 */
+				length = (le32_to_cpu(rx_ring[rx_new].status) >> 16);
+
+				/* Pass the packet up to the protocol
+				 * layers.
+				 */
+				NetReceive(NetRxPackets[rx_new], length - 4);
+			}
+
+			/* Change buffer ownership for this frame, back
+			 * to the adapter.
+			 */
+			rx_ring[rx_new].status = cpu_to_le32(R_OWN);
+		}
+
+		/* Update entry information.
+		 */
+		rx_new = (rx_new + 1) % rxRingSize;
+	}
+
+	return length;
+}
+
+static void dc21x4x_halt(struct eth_device* dev)
+{
+	int		devbusfn = (int) dev->priv;
+
+	STOP_DE4X5(dev);
+	OUTL(dev, 0, DE4X5_SICR);
+
+	pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
+}
+
+static void send_setup_frame(struct eth_device* dev, bd_t *bis)
+{
+	int		i;
+	char	setup_frame[SETUP_FRAME_LEN];
+	char 	*pa = &setup_frame[0];
+
+	memset(pa, 0xff, SETUP_FRAME_LEN);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		*(pa + (i & 1)) = dev->enetaddr[i];
+		if (i & 0x01) {
+			pa += 4;
+		}
+	}
+
+	for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+		if (i >= TOUT_LOOP) {
+			printf("%s: tx error buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) &setup_frame[0]));
+	tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET| SETUP_FRAME_LEN);
+	tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+	OUTL(dev, POLL_DEMAND, DE4X5_TPD);
+
+	for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+		if (i >= TOUT_LOOP) {
+			printf("%s: tx buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
+		printf("TX error status2 = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status));
+	}
+	tx_new = (tx_new+1) % NUM_TX_DESC;
+
+Done:
+	return;
+}
+
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+/* SROM Read and write routines.
+ */
+static void
+sendto_srom(struct eth_device* dev, u_int command, u_long addr)
+{
+	OUTL(dev, command, addr);
+	udelay(1);
+}
+
+static int
+getfrom_srom(struct eth_device* dev, u_long addr)
+{
+	s32 tmp;
+
+	tmp = INL(dev, addr);
+	udelay(1);
+
+	return tmp;
+}
+
+/* Note: this routine returns extra data bits for size detection. */
+static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	int read_cmd = location | (SROM_READ_CMD << addr_len);
+
+	sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
+	sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+#ifdef DEBUG_SROM
+	printf(" EEPROM read at %d ", location);
+#endif
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval, ioaddr);
+		udelay(10);
+		sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, ioaddr);
+		udelay(10);
+#ifdef DEBUG_SROM2
+		printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+		retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+	}
+
+	sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+#ifdef DEBUG_SROM2
+	printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
+#endif
+
+	for (i = 16; i > 0; i--) {
+		sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+		udelay(10);
+#ifdef DEBUG_SROM2
+		printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+		retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+		sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+		udelay(10);
+	}
+
+	/* Terminate the EEPROM access. */
+	sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
+
+#ifdef DEBUG_SROM2
+	printf(" EEPROM value at %d is %5.5x.\n", location, retval);
+#endif
+
+	return retval;
+}
+#endif	/* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+
+/* This executes a generic EEPROM command, typically a write or write
+ * enable. It returns the data output from the EEPROM, and thus may
+ * also be used for reads.
+ */
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd_len)
+{
+	unsigned retval = 0;
+
+#ifdef DEBUG_SROM
+	printf(" EEPROM op 0x%x: ", cmd);
+#endif
+
+	sendto_srom(dev,SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+
+	/* Shift the command bits out. */
+	do {
+		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+		sendto_srom(dev,dataval, ioaddr);
+		udelay(10);
+
+#ifdef DEBUG_SROM2
+		printf("%X", getfrom_srom(dev,ioaddr) & 15);
+#endif
+
+		sendto_srom(dev,dataval | DT_CLK, ioaddr);
+		udelay(10);
+		retval = (retval << 1) | ((getfrom_srom(dev,ioaddr) & EE_DATA_READ) ? 1 : 0);
+	} while (--cmd_len >= 0);
+	sendto_srom(dev,SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+	/* Terminate the EEPROM access. */
+	sendto_srom(dev,SROM_RD | SROM_SR, ioaddr);
+
+#ifdef DEBUG_SROM
+	printf(" EEPROM result is 0x%5.5x.\n", retval);
+#endif
+
+	return retval;
+}
+#endif	/* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
+{
+	int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+	return do_eeprom_cmd(dev, ioaddr,
+			     (((SROM_READ_CMD << ee_addr_size) | index) << 16)
+			     | 0xffff, 3 + ee_addr_size + 16);
+}
+#endif	/* CONFIG_TULIP_FIX_DAVICOM */
+
+#ifdef UPDATE_SROM
+static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value)
+{
+	int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+	int i;
+	unsigned short newval;
+
+	udelay(10*1000); /* test-only */
+
+#ifdef DEBUG_SROM
+	printf("ee_addr_size=%d.\n", ee_addr_size);
+	printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
+#endif
+
+	/* Enable programming modes. */
+	do_eeprom_cmd(dev, ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size);
+
+	/* Do the actual write. */
+	do_eeprom_cmd(dev, ioaddr,
+		      (((SROM_WRITE_CMD<<ee_addr_size)|index) << 16) | new_value,
+		      3 + ee_addr_size + 16);
+
+	/* Poll for write finished. */
+	sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+	for (i = 0; i < 10000; i++)			/* Typical 2000 ticks */
+		if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
+			break;
+
+#ifdef DEBUG_SROM
+	printf(" Write finished after %d ticks.\n", i);
+#endif
+
+	/* Disable programming. */
+	do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size-4)), 3 + ee_addr_size);
+
+	/* And read the result. */
+	newval = do_eeprom_cmd(dev, ioaddr,
+			       (((SROM_READ_CMD<<ee_addr_size)|index) << 16)
+			       | 0xffff, 3 + ee_addr_size + 16);
+#ifdef DEBUG_SROM
+	printf("  New value at offset %d is %4.4x.\n", index, newval);
+#endif
+	return 1;
+}
+#endif
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static void read_hw_addr(struct eth_device *dev, bd_t *bis)
+{
+	u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
+	int i, j = 0;
+
+	for (i = 0; i < (ETH_ALEN >> 1); i++) {
+		tmp = read_srom(dev, DE4X5_APROM, ((SROM_HWADD >> 1) + i));
+		*p = le16_to_cpu(tmp);
+		j += *p++;
+	}
+
+	if ((j == 0) || (j == 0x2fffd)) {
+		memset (dev->enetaddr, 0, ETH_ALEN);
+		debug ("Warning: can't read HW address from SROM.\n");
+		goto Done;
+	}
+
+	return;
+
+Done:
+#ifdef UPDATE_SROM
+	update_srom(dev, bis);
+#endif
+	return;
+}
+#endif	/* CONFIG_TULIP_FIX_DAVICOM */
+
+#ifdef UPDATE_SROM
+static void update_srom(struct eth_device *dev, bd_t *bis)
+{
+	int i;
+	static unsigned short eeprom[0x40] = {
+		0x140b, 0x6610, 0x0000, 0x0000, 	/* 00 */
+		0x0000, 0x0000, 0x0000, 0x0000, 	/* 04 */
+		0x00a3, 0x0103, 0x0000, 0x0000,  	/* 08 */
+		0x0000, 0x1f00, 0x0000, 0x0000, 	/* 0c */
+		0x0108, 0x038d, 0x0000, 0x0000,  	/* 10 */
+		0xe078, 0x0001, 0x0040, 0x0018, 	/* 14 */
+		0x0000, 0x0000, 0x0000, 0x0000,  	/* 18 */
+		0x0000, 0x0000, 0x0000, 0x0000, 	/* 1c */
+		0x0000, 0x0000, 0x0000, 0x0000,  	/* 20 */
+		0x0000, 0x0000, 0x0000, 0x0000, 	/* 24 */
+		0x0000, 0x0000, 0x0000, 0x0000,  	/* 28 */
+		0x0000, 0x0000, 0x0000, 0x0000, 	/* 2c */
+		0x0000, 0x0000, 0x0000, 0x0000,  	/* 30 */
+		0x0000, 0x0000, 0x0000, 0x0000, 	/* 34 */
+		0x0000, 0x0000, 0x0000, 0x0000,  	/* 38 */
+		0x0000, 0x0000, 0x0000, 0x4e07,		/* 3c */
+	};
+
+	/* Ethernet Addr... */
+	eeprom[0x0a] = ((bis->bi_enetaddr[1] & 0xff) << 8) | (bis->bi_enetaddr[0] & 0xff);
+	eeprom[0x0b] = ((bis->bi_enetaddr[3] & 0xff) << 8) | (bis->bi_enetaddr[2] & 0xff);
+	eeprom[0x0c] = ((bis->bi_enetaddr[5] & 0xff) << 8) | (bis->bi_enetaddr[4] & 0xff);
+
+	for (i=0; i<0x40; i++)
+	{
+		write_srom(dev, DE4X5_APROM, i, eeprom[i]);
+	}
+}
+#endif	/* UPDATE_SROM */
+
+#endif
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
new file mode 100644
index 0000000..6131b5c
--- /dev/null
+++ b/drivers/net/dm9000x.c
@@ -0,0 +1,620 @@
+/*
+  dm9000.c: Version 1.2 12/15/2003
+
+	A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
+	Copyright (C) 1997  Sten Wang
+
+	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.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+  (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+
+V0.11	06/20/2001	REG_0A bit3=1, default enable BP with DA match
+	06/22/2001 	Support DM9801 progrmming
+	 	 	E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
+		 	E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
+     		R17 = (R17 & 0xfff0) | NF + 3
+		 	E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
+     		R17 = (R17 & 0xfff0) | NF
+
+v1.00               	modify by simon 2001.9.5
+	                change for kernel 2.4.x
+
+v1.1   11/09/2001      	fix force mode bug
+
+v1.2   03/18/2003       Weilun Huang <weilun_huang@davicom.com.tw>:
+			Fixed phy reset.
+			Added tx/rx 32 bit mode.
+			Cleaned up for kernel merge.
+
+--------------------------------------
+
+       12/15/2003       Initial port to u-boot by Sascha Hauer <saschahauer@web.de>
+
+TODO: Homerun NIC and longrun NIC are not functional, only internal at the
+      moment.
+*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_DRIVER_DM9000
+
+#include "dm9000x.h"
+
+/* Board/System/Debug information/definition ---------------- */
+
+#define DM9801_NOISE_FLOOR	0x08
+#define DM9802_NOISE_FLOOR	0x05
+
+/* #define CONFIG_DM9000_DEBUG */
+
+#ifdef CONFIG_DM9000_DEBUG
+#define DM9000_DBG(fmt,args...) printf(fmt ,##args)
+#else				/*  */
+#define DM9000_DBG(fmt,args...)
+#endif				/*  */
+enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD =
+	    1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO =
+	    8, DM9000_1M_HPNA = 0x10
+};
+enum DM9000_NIC_TYPE { FASTETHER_NIC = 0, HOMERUN_NIC = 1, LONGRUN_NIC = 2
+};
+
+/* Structure/enum declaration ------------------------------- */
+typedef struct board_info {
+	u32 runt_length_counter;	/* counter: RX length < 64byte */
+	u32 long_length_counter;	/* counter: RX length > 1514byte */
+	u32 reset_counter;	/* counter: RESET */
+	u32 reset_tx_timeout;	/* RESET caused by TX Timeout */
+	u32 reset_rx_status;	/* RESET caused by RX Statsus wrong */
+	u16 tx_pkt_cnt;
+	u16 queue_start_addr;
+	u16 dbug_cnt;
+	u8 phy_addr;
+	u8 device_wait_reset;	/* device state */
+	u8 nic_type;		/* NIC type */
+	unsigned char srom[128];
+} board_info_t;
+board_info_t dmfe_info;
+
+/* For module input parameter */
+static int media_mode = DM9000_AUTO;
+static u8 nfloor = 0;
+
+/* function declaration ------------------------------------- */
+int eth_init(bd_t * bd);
+int eth_send(volatile void *, int);
+int eth_rx(void);
+void eth_halt(void);
+static int dm9000_probe(void);
+static u16 phy_read(int);
+static void phy_write(int, u16);
+u16 read_srom_word(int);
+static u8 DM9000_ior(int);
+static void DM9000_iow(int reg, u8 value);
+
+/* DM9000 network board routine ---------------------------- */
+
+#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
+#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
+#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
+#define DM9000_inb(r) (*(volatile u8 *)r)
+#define DM9000_inw(r) (*(volatile u16 *)r)
+#define DM9000_inl(r) (*(volatile u32 *)r)
+
+#ifdef CONFIG_DM9000_DEBUG
+static void
+dump_regs(void)
+{
+	DM9000_DBG("\n");
+	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
+	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(1));
+	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(2));
+	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(3));
+	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
+	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(5));
+	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(6));
+	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(ISR));
+	DM9000_DBG("\n");
+}
+#endif				/*  */
+
+/*
+  Search DM9000 board, allocate space and register it
+*/
+int
+dm9000_probe(void)
+{
+	u32 id_val;
+	id_val = DM9000_ior(DM9000_VIDL);
+	id_val |= DM9000_ior(DM9000_VIDH) << 8;
+	id_val |= DM9000_ior(DM9000_PIDL) << 16;
+	id_val |= DM9000_ior(DM9000_PIDH) << 24;
+	if (id_val == DM9000_ID) {
+		printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
+		       id_val);
+		return 0;
+	} else {
+		printf("dm9000 not found at 0x%08x id: 0x%08x\n",
+		       CONFIG_DM9000_BASE, id_val);
+		return -1;
+	}
+}
+
+/* Set PHY operationg mode
+*/
+static void
+set_PHY_mode(void)
+{
+	u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
+	if (!(media_mode & DM9000_AUTO)) {
+		switch (media_mode) {
+		case DM9000_10MHD:
+			phy_reg4 = 0x21;
+			phy_reg0 = 0x0000;
+			break;
+		case DM9000_10MFD:
+			phy_reg4 = 0x41;
+			phy_reg0 = 0x1100;
+			break;
+		case DM9000_100MHD:
+			phy_reg4 = 0x81;
+			phy_reg0 = 0x2000;
+			break;
+		case DM9000_100MFD:
+			phy_reg4 = 0x101;
+			phy_reg0 = 0x3100;
+			break;
+		}
+		phy_write(4, phy_reg4);	/* Set PHY media mode */
+		phy_write(0, phy_reg0);	/*  Tmp */
+	}
+	DM9000_iow(DM9000_GPCR, 0x01);	/* Let GPIO0 output */
+	DM9000_iow(DM9000_GPR, 0x00);	/* Enable PHY */
+}
+
+/*
+	Init HomeRun DM9801
+*/
+static void
+program_dm9801(u16 HPNA_rev)
+{
+	__u16 reg16, reg17, reg24, reg25;
+	if (!nfloor)
+		nfloor = DM9801_NOISE_FLOOR;
+	reg16 = phy_read(16);
+	reg17 = phy_read(17);
+	reg24 = phy_read(24);
+	reg25 = phy_read(25);
+	switch (HPNA_rev) {
+	case 0xb900:		/* DM9801 E3 */
+		reg16 |= 0x1000;
+		reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000;
+		break;
+	case 0xb901:		/* DM9801 E4 */
+		reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200;
+		reg17 = (reg17 & 0xfff0) + nfloor + 3;
+		break;
+	case 0xb902:		/* DM9801 E5 */
+	case 0xb903:		/* DM9801 E6 */
+	default:
+		reg16 |= 0x1000;
+		reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200;
+		reg17 = (reg17 & 0xfff0) + nfloor;
+	}
+	phy_write(16, reg16);
+	phy_write(17, reg17);
+	phy_write(25, reg25);
+}
+
+/*
+	Init LongRun DM9802
+*/
+static void
+program_dm9802(void)
+{
+	__u16 reg25;
+	if (!nfloor)
+		nfloor = DM9802_NOISE_FLOOR;
+	reg25 = phy_read(25);
+	reg25 = (reg25 & 0xff00) + nfloor;
+	phy_write(25, reg25);
+}
+
+/* Identify NIC type
+*/
+static void
+identify_nic(void)
+{
+	struct board_info *db = &dmfe_info;	/* Point a board information structure */
+	u16 phy_reg3;
+	DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
+	phy_reg3 = phy_read(3);
+	switch (phy_reg3 & 0xfff0) {
+	case 0xb900:
+		if (phy_read(31) == 0x4404) {
+			db->nic_type = HOMERUN_NIC;
+			program_dm9801(phy_reg3);
+			DM9000_DBG("found homerun NIC\n");
+		} else {
+			db->nic_type = LONGRUN_NIC;
+			DM9000_DBG("found longrun NIC\n");
+			program_dm9802();
+		}
+		break;
+	default:
+		db->nic_type = FASTETHER_NIC;
+		break;
+	}
+	DM9000_iow(DM9000_NCR, 0);
+}
+
+/* General Purpose dm9000 reset routine */
+static void
+dm9000_reset(void)
+{
+	DM9000_DBG("resetting\n");
+	DM9000_iow(DM9000_NCR, NCR_RST);
+	udelay(1000);		/* delay 1ms */
+}
+
+/* Initilize dm9000 board
+*/
+int
+eth_init(bd_t * bd)
+{
+	int i, oft, lnk;
+	DM9000_DBG("eth_init()\n");
+
+	/* RESET device */
+	dm9000_reset();
+	dm9000_probe();
+
+	/* NIC Type: FASTETHER, HOMERUN, LONGRUN */
+	identify_nic();
+
+	/* GPIO0 on pre-activate PHY */
+	DM9000_iow(DM9000_GPR, 0x00);	/*REG_1F bit0 activate phyxcer */
+
+	/* Set PHY */
+	set_PHY_mode();
+
+	/* Program operating register */
+	DM9000_iow(DM9000_NCR, 0x0);	/* only intern phy supported by now */
+	DM9000_iow(DM9000_TCR, 0);	/* TX Polling clear */
+	DM9000_iow(DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
+	DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));	/* Flow Control : High/Low Water */
+	DM9000_iow(DM9000_FCR, 0x0);	/* SH FIXME: This looks strange! Flow Control */
+	DM9000_iow(DM9000_SMCR, 0);	/* Special Mode */
+	DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);	/* clear TX status */
+	DM9000_iow(DM9000_ISR, 0x0f);	/* Clear interrupt status */
+
+	/* Set Node address */
+	for (i = 0; i < 6; i++)
+		((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
+
+	if (is_zero_ether_addr(bd->bi_enetaddr) ||
+	    is_multicast_ether_addr(bd->bi_enetaddr)) {
+		/* try reading from environment */
+		u8 i;
+		char *s, *e;
+		s = getenv ("ethaddr");
+		for (i = 0; i < 6; ++i) {
+			bd->bi_enetaddr[i] = s ?
+				simple_strtoul (s, &e, 16) : 0;
+			if (s)
+				s = (*e) ? e + 1 : e;
+		}
+	}
+
+	printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
+	       bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
+	       bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
+	for (i = 0, oft = 0x10; i < 6; i++, oft++)
+		DM9000_iow(oft, bd->bi_enetaddr[i]);
+	for (i = 0, oft = 0x16; i < 8; i++, oft++)
+		DM9000_iow(oft, 0xff);
+
+	/* read back mac, just to be sure */
+	for (i = 0, oft = 0x10; i < 6; i++, oft++)
+		DM9000_DBG("%02x:", DM9000_ior(oft));
+	DM9000_DBG("\n");
+
+	/* Activate DM9000 */
+	DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);	/* RX enable */
+	DM9000_iow(DM9000_IMR, IMR_PAR);	/* Enable TX/RX interrupt mask */
+	i = 0;
+	while (!(phy_read(1) & 0x20)) {	/* autonegation complete bit */
+		udelay(1000);
+		i++;
+		if (i == 10000) {
+			printf("could not establish link\n");
+			return 0;
+		}
+	}
+
+	/* see what we've got */
+	lnk = phy_read(17) >> 12;
+	printf("operating at ");
+	switch (lnk) {
+	case 1:
+		printf("10M half duplex ");
+		break;
+	case 2:
+		printf("10M full duplex ");
+		break;
+	case 4:
+		printf("100M half duplex ");
+		break;
+	case 8:
+		printf("100M full duplex ");
+		break;
+	default:
+		printf("unknown: %d ", lnk);
+		break;
+	}
+	printf("mode\n");
+	return 0;
+}
+
+/*
+  Hardware start transmission.
+  Send a packet to media from the upper layer.
+*/
+int
+eth_send(volatile void *packet, int length)
+{
+	char *data_ptr;
+	u32 tmplen, i;
+	int tmo;
+	DM9000_DBG("eth_send: length: %d\n", length);
+	for (i = 0; i < length; i++) {
+		if (i % 8 == 0)
+			DM9000_DBG("\nSend: 02x: ", i);
+		DM9000_DBG("%02x ", ((unsigned char *) packet)[i]);
+	} DM9000_DBG("\n");
+
+	/* Move data to DM9000 TX RAM */
+	data_ptr = (char *) packet;
+	DM9000_outb(DM9000_MWCMD, DM9000_IO);
+
+#ifdef CONFIG_DM9000_USE_8BIT
+	/* Byte mode */
+	for (i = 0; i < length; i++)
+		DM9000_outb((data_ptr[i] & 0xff), DM9000_DATA);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_16BIT
+	tmplen = (length + 1) / 2;
+	for (i = 0; i < tmplen; i++)
+		DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_32BIT
+	tmplen = (length + 3) / 4;
+	for (i = 0; i < tmplen; i++)
+		DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
+
+#endif				/*  */
+
+	/* Set TX length to DM9000 */
+	DM9000_iow(DM9000_TXPLL, length & 0xff);
+	DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
+
+	/* Issue TX polling command */
+	DM9000_iow(DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */
+
+	/* wait for end of transmission */
+	tmo = get_timer(0) + 5 * CFG_HZ;
+	while (DM9000_ior(DM9000_TCR) & TCR_TXREQ) {
+		if (get_timer(0) >= tmo) {
+			printf("transmission timeout\n");
+			break;
+		}
+	}
+	DM9000_DBG("transmit done\n\n");
+	return 0;
+}
+
+/*
+  Stop the interface.
+  The interface is stopped when it is brought.
+*/
+void
+eth_halt(void)
+{
+	DM9000_DBG("eth_halt\n");
+
+	/* RESET devie */
+	phy_write(0, 0x8000);	/* PHY RESET */
+	DM9000_iow(DM9000_GPR, 0x01);	/* Power-Down PHY */
+	DM9000_iow(DM9000_IMR, 0x80);	/* Disable all interrupt */
+	DM9000_iow(DM9000_RCR, 0x00);	/* Disable RX */
+}
+
+/*
+  Received a packet and pass to upper layer
+*/
+int
+eth_rx(void)
+{
+	u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
+	u16 RxStatus, RxLen = 0;
+	u32 tmplen, i;
+#ifdef CONFIG_DM9000_USE_32BIT
+	u32 tmpdata;
+#endif
+
+	/* Check packet ready or not */
+	DM9000_ior(DM9000_MRCMDX);	/* Dummy read */
+	rxbyte = DM9000_inb(DM9000_DATA);	/* Got most updated data */
+	if (rxbyte == 0)
+		return 0;
+
+	/* Status check: this byte must be 0 or 1 */
+	if (rxbyte > 1) {
+		DM9000_iow(DM9000_RCR, 0x00);	/* Stop Device */
+		DM9000_iow(DM9000_ISR, 0x80);	/* Stop INT request */
+		DM9000_DBG("rx status check: %d\n", rxbyte);
+	}
+	DM9000_DBG("receiving packet\n");
+
+	/* A packet ready now  & Get status/length */
+	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+
+#ifdef CONFIG_DM9000_USE_8BIT
+	RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
+	RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_16BIT
+	RxStatus = DM9000_inw(DM9000_DATA);
+	RxLen = DM9000_inw(DM9000_DATA);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_32BIT
+	tmpdata = DM9000_inl(DM9000_DATA);
+	RxStatus = tmpdata;
+	RxLen = tmpdata >> 16;
+
+#endif				/*  */
+	DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
+
+	/* Move data from DM9000 */
+	/* Read received packet from RX SRAM */
+#ifdef CONFIG_DM9000_USE_8BIT
+	for (i = 0; i < RxLen; i++)
+		rdptr[i] = DM9000_inb(DM9000_DATA);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_16BIT
+	tmplen = (RxLen + 1) / 2;
+	for (i = 0; i < tmplen; i++)
+		((u16 *) rdptr)[i] = DM9000_inw(DM9000_DATA);
+
+#endif				/*  */
+#ifdef CONFIG_DM9000_USE_32BIT
+	tmplen = (RxLen + 3) / 4;
+	for (i = 0; i < tmplen; i++)
+		((u32 *) rdptr)[i] = DM9000_inl(DM9000_DATA);
+
+#endif				/*  */
+	if ((RxStatus & 0xbf00) || (RxLen < 0x40)
+	    || (RxLen > DM9000_PKT_MAX)) {
+		if (RxStatus & 0x100) {
+			printf("rx fifo error\n");
+		}
+		if (RxStatus & 0x200) {
+			printf("rx crc error\n");
+		}
+		if (RxStatus & 0x8000) {
+			printf("rx length error\n");
+		}
+		if (RxLen > DM9000_PKT_MAX) {
+			printf("rx length too big\n");
+			dm9000_reset();
+		}
+	} else {
+
+		/* Pass to upper layer */
+		DM9000_DBG("passing packet to upper layer\n");
+		NetReceive(NetRxPackets[0], RxLen);
+		return RxLen;
+	}
+	return 0;
+}
+
+/*
+  Read a word data from SROM
+*/
+u16
+read_srom_word(int offset)
+{
+	DM9000_iow(DM9000_EPAR, offset);
+	DM9000_iow(DM9000_EPCR, 0x4);
+	udelay(8000);
+	DM9000_iow(DM9000_EPCR, 0x0);
+	return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
+}
+
+void
+write_srom_word(int offset, u16 val)
+{
+	DM9000_iow(DM9000_EPAR, offset);
+	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
+	DM9000_iow(DM9000_EPDRL, (val & 0xff));
+	DM9000_iow(DM9000_EPCR, 0x12);
+	udelay(8000);
+	DM9000_iow(DM9000_EPCR, 0);
+}
+
+
+/*
+   Read a byte from I/O port
+*/
+static u8
+DM9000_ior(int reg)
+{
+	DM9000_outb(reg, DM9000_IO);
+	return DM9000_inb(DM9000_DATA);
+}
+
+/*
+   Write a byte to I/O port
+*/
+static void
+DM9000_iow(int reg, u8 value)
+{
+	DM9000_outb(reg, DM9000_IO);
+	DM9000_outb(value, DM9000_DATA);
+}
+
+/*
+   Read a word from phyxcer
+*/
+static u16
+phy_read(int reg)
+{
+	u16 val;
+
+	/* Fill the phyxcer register into REG_0C */
+	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
+	udelay(100);		/* Wait read complete */
+	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
+	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
+
+	/* The read data keeps on REG_0D & REG_0E */
+	DM9000_DBG("phy_read(%d): %d\n", reg, val);
+	return val;
+}
+
+/*
+   Write a word to phyxcer
+*/
+static void
+phy_write(int reg, u16 value)
+{
+
+	/* Fill the phyxcer register into REG_0C */
+	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+
+	/* Fill the written data into REG_0D & REG_0E */
+	DM9000_iow(DM9000_EPDRL, (value & 0xff));
+	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
+	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
+	udelay(500);		/* Wait write complete */
+	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
+	DM9000_DBG("phy_write(reg:%d, value:%d)\n", reg, value);
+}
+#endif				/* CONFIG_DRIVER_DM9000 */
diff --git a/drivers/net/dm9000x.h b/drivers/net/dm9000x.h
new file mode 100644
index 0000000..f47ff8c
--- /dev/null
+++ b/drivers/net/dm9000x.h
@@ -0,0 +1,119 @@
+/*
+ * dm9000 Ethernet
+ */
+
+#ifdef CONFIG_DRIVER_DM9000
+
+#define DM9000_ID		0x90000A46
+#define DM9000_PKT_MAX		1536	/* Received packet max size */
+#define DM9000_PKT_RDY		0x01	/* Packet ready to receive */
+
+/* although the registers are 16 bit, they are 32-bit aligned.
+ */
+
+#define DM9000_NCR             0x00
+#define DM9000_NSR             0x01
+#define DM9000_TCR             0x02
+#define DM9000_TSR1            0x03
+#define DM9000_TSR2            0x04
+#define DM9000_RCR             0x05
+#define DM9000_RSR             0x06
+#define DM9000_ROCR            0x07
+#define DM9000_BPTR            0x08
+#define DM9000_FCTR            0x09
+#define DM9000_FCR             0x0A
+#define DM9000_EPCR            0x0B
+#define DM9000_EPAR            0x0C
+#define DM9000_EPDRL           0x0D
+#define DM9000_EPDRH           0x0E
+#define DM9000_WCR             0x0F
+
+#define DM9000_PAR             0x10
+#define DM9000_MAR             0x16
+
+#define DM9000_GPCR			0x1e
+#define DM9000_GPR             0x1f
+#define DM9000_TRPAL           0x22
+#define DM9000_TRPAH           0x23
+#define DM9000_RWPAL           0x24
+#define DM9000_RWPAH           0x25
+
+#define DM9000_VIDL            0x28
+#define DM9000_VIDH            0x29
+#define DM9000_PIDL            0x2A
+#define DM9000_PIDH            0x2B
+
+#define DM9000_CHIPR           0x2C
+#define DM9000_SMCR            0x2F
+
+#define DM9000_PHY		0x40	/* PHY address 0x01 */
+
+#define DM9000_MRCMDX          0xF0
+#define DM9000_MRCMD           0xF2
+#define DM9000_MRRL            0xF4
+#define DM9000_MRRH            0xF5
+#define DM9000_MWCMDX			0xF6
+#define DM9000_MWCMD           0xF8
+#define DM9000_MWRL            0xFA
+#define DM9000_MWRH            0xFB
+#define DM9000_TXPLL           0xFC
+#define DM9000_TXPLH           0xFD
+#define DM9000_ISR             0xFE
+#define DM9000_IMR             0xFF
+
+#define NCR_EXT_PHY		(1<<7)
+#define NCR_WAKEEN		(1<<6)
+#define NCR_FCOL		(1<<4)
+#define NCR_FDX			(1<<3)
+#define NCR_LBK			(3<<1)
+#define NCR_RST			(1<<0)
+
+#define NSR_SPEED		(1<<7)
+#define NSR_LINKST		(1<<6)
+#define NSR_WAKEST		(1<<5)
+#define NSR_TX2END		(1<<3)
+#define NSR_TX1END		(1<<2)
+#define NSR_RXOV		(1<<1)
+
+#define TCR_TJDIS		(1<<6)
+#define TCR_EXCECM		(1<<5)
+#define TCR_PAD_DIS2	(1<<4)
+#define TCR_CRC_DIS2	(1<<3)
+#define TCR_PAD_DIS1	(1<<2)
+#define TCR_CRC_DIS1	(1<<1)
+#define TCR_TXREQ		(1<<0)
+
+#define TSR_TJTO		(1<<7)
+#define TSR_LC			(1<<6)
+#define TSR_NC			(1<<5)
+#define TSR_LCOL		(1<<4)
+#define TSR_COL			(1<<3)
+#define TSR_EC			(1<<2)
+
+#define RCR_WTDIS		(1<<6)
+#define RCR_DIS_LONG	(1<<5)
+#define RCR_DIS_CRC		(1<<4)
+#define RCR_ALL			(1<<3)
+#define RCR_RUNT		(1<<2)
+#define RCR_PRMSC		(1<<1)
+#define RCR_RXEN		(1<<0)
+
+#define RSR_RF			(1<<7)
+#define RSR_MF			(1<<6)
+#define RSR_LCS			(1<<5)
+#define RSR_RWTO		(1<<4)
+#define RSR_PLE			(1<<3)
+#define RSR_AE			(1<<2)
+#define RSR_CE			(1<<1)
+#define RSR_FOE			(1<<0)
+
+#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
+#define FCTR_LWOT(ot)	( ot & 0xf )
+
+#define IMR_PAR			(1<<7)
+#define IMR_ROOM		(1<<3)
+#define IMR_ROM			(1<<2)
+#define IMR_PTM			(1<<1)
+#define IMR_PRM			(1<<0)
+
+#endif
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
new file mode 100644
index 0000000..f0741da
--- /dev/null
+++ b/drivers/net/e1000.c
@@ -0,0 +1,3016 @@
+/**************************************************************************
+Inter Pro 1000 for ppcboot/das-u-boot
+Drivers are port from Intel's Linux driver e1000-4.3.15
+and from Etherboot pro 1000 driver by mrakes at vivato dot net
+tested on both gig copper and gig fiber boards
+***************************************************************************/
+/*******************************************************************************
+
+
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+
+  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.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+/*
+ *  Copyright (C) Archway Digital Solutions.
+ *
+ *  written by Chrsitopher Li <cli at arcyway dot com> or <chrisl at gnuchina dot org>
+ *  2/9/2002
+ *
+ *  Copyright (C) Linux Networx.
+ *  Massive upgrade to work with the new intel gigabit NICs.
+ *  <ebiederman at lnxi dot com>
+ */
+
+#include "e1000.h"
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_E1000)
+
+#define TOUT_LOOP   100000
+
+#undef	virt_to_bus
+#define	virt_to_bus(x)	((unsigned long)x)
+#define bus_to_phys(devno, a)	pci_mem_to_phys(devno, a)
+#define mdelay(n)       udelay((n)*1000)
+
+#define E1000_DEFAULT_PBA    0x00000030
+
+/* NIC specific static variables go here */
+
+static char tx_pool[128 + 16];
+static char rx_pool[128 + 16];
+static char packet[2096];
+
+static struct e1000_tx_desc *tx_base;
+static struct e1000_rx_desc *rx_base;
+
+static int tx_tail;
+static int rx_tail, rx_last;
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82542},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_FIBER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_COPPER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544EI_COPPER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544EI_FIBER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_COPPER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_LOM},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_COPPER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
+};
+
+/* Function forward declarations */
+static int e1000_setup_link(struct eth_device *nic);
+static int e1000_setup_fiber_link(struct eth_device *nic);
+static int e1000_setup_copper_link(struct eth_device *nic);
+static int e1000_phy_setup_autoneg(struct e1000_hw *hw);
+static void e1000_config_collision_dist(struct e1000_hw *hw);
+static int e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int e1000_config_fc_after_link_up(struct e1000_hw *hw);
+static int e1000_check_for_link(struct eth_device *nic);
+static int e1000_wait_autoneg(struct e1000_hw *hw);
+static void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
+				       uint16_t * duplex);
+static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
+			      uint16_t * phy_data);
+static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
+			       uint16_t phy_data);
+static void e1000_phy_hw_reset(struct e1000_hw *hw);
+static int e1000_phy_reset(struct e1000_hw *hw);
+static int e1000_detect_gig_phy(struct e1000_hw *hw);
+
+#define E1000_WRITE_REG(a, reg, value) (writel((value), ((a)->hw_addr + E1000_##reg)))
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_##reg))
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\
+			writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))))
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+	readl((a)->hw_addr + E1000_##reg + ((offset) << 2)))
+#define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}
+
+#ifndef CONFIG_AP1000 /* remove for warnings */
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+{
+	/* Raise the clock input to the EEPROM (by setting the SK bit), and then
+	 * wait 50 microseconds.
+	 */
+	*eecd = *eecd | E1000_EECD_SK;
+	E1000_WRITE_REG(hw, EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+{
+	/* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+	 * wait 50 microseconds.
+	 */
+	*eecd = *eecd & ~E1000_EECD_SK;
+	E1000_WRITE_REG(hw, EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count)
+{
+	uint32_t eecd;
+	uint32_t mask;
+
+	/* We need to shift "count" bits out to the EEPROM. So, value in the
+	 * "data" parameter will be shifted out to the EEPROM one bit at a time.
+	 * In order to do this, "data" must be broken down into bits.
+	 */
+	mask = 0x01 << (count - 1);
+	eecd = E1000_READ_REG(hw, EECD);
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	do {
+		/* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+		 * and then raising and then lowering the clock (the SK bit controls
+		 * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
+		 * by setting "DI" to "0" and then raising and then lowering the clock.
+		 */
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		E1000_WRITE_REG(hw, EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+
+		udelay(50);
+
+		e1000_raise_ee_clk(hw, &eecd);
+		e1000_lower_ee_clk(hw, &eecd);
+
+		mask = mask >> 1;
+
+	} while (mask);
+
+	/* We leave the "DI" bit set to "0" when we leave this routine. */
+	eecd &= ~E1000_EECD_DI;
+	E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+	uint32_t i;
+	uint16_t data;
+
+	/* In order to read a register from the EEPROM, we need to shift 16 bits
+	 * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+	 * the EEPROM (setting the SK bit), and then reading the value of the "DO"
+	 * bit.  During this "shifting in" process the "DI" bit should always be
+	 * clear..
+	 */
+
+	eecd = E1000_READ_REG(hw, EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < 16; i++) {
+		data = data << 1;
+		e1000_raise_ee_clk(hw, &eecd);
+
+		eecd = E1000_READ_REG(hw, EECD);
+
+		eecd &= ~(E1000_EECD_DI);
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		e1000_lower_ee_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+
+	eecd = E1000_READ_REG(hw, EECD);
+
+	/* Clear SK and DI */
+	eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+	E1000_WRITE_REG(hw, EECD, eecd);
+
+	/* Set CS */
+	eecd |= E1000_EECD_CS;
+	E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+
+	eecd = E1000_READ_REG(hw, EECD);
+
+	/* Deselct EEPROM */
+	eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+	E1000_WRITE_REG(hw, EECD, eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+
+	/* Clock high */
+	eecd |= E1000_EECD_SK;
+	E1000_WRITE_REG(hw, EECD, eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+
+	/* Select EEPROM */
+	eecd |= E1000_EECD_CS;
+	E1000_WRITE_REG(hw, EECD, eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+
+	/* Clock low */
+	eecd &= ~E1000_EECD_SK;
+	E1000_WRITE_REG(hw, EECD, eecd);
+	E1000_WRITE_FLUSH(hw);
+	udelay(50);
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ *****************************************************************************/
+static int
+e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t * data)
+{
+	uint32_t eecd;
+	uint32_t i = 0;
+	int large_eeprom = FALSE;
+
+	/* Request EEPROM Access */
+	if (hw->mac_type > e1000_82544) {
+		eecd = E1000_READ_REG(hw, EECD);
+		if (eecd & E1000_EECD_SIZE)
+			large_eeprom = TRUE;
+		eecd |= E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, EECD, eecd);
+		eecd = E1000_READ_REG(hw, EECD);
+		while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+			i++;
+			udelay(10);
+			eecd = E1000_READ_REG(hw, EECD);
+		}
+		if (!(eecd & E1000_EECD_GNT)) {
+			eecd &= ~E1000_EECD_REQ;
+			E1000_WRITE_REG(hw, EECD, eecd);
+			DEBUGOUT("Could not acquire EEPROM grant\n");
+			return -E1000_ERR_EEPROM;
+		}
+	}
+
+	/*  Prepare the EEPROM for reading  */
+	e1000_setup_eeprom(hw);
+
+	/*  Send the READ command (opcode + addr)  */
+	e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+	e1000_shift_out_ee_bits(hw, offset, (large_eeprom) ? 8 : 6);
+
+	/* Read the data */
+	*data = e1000_shift_in_ee_bits(hw);
+
+	/* End this read operation */
+	e1000_standby_eeprom(hw);
+
+	/* Stop requesting EEPROM access */
+	if (hw->mac_type > e1000_82544) {
+		eecd = E1000_READ_REG(hw, EECD);
+		eecd &= ~E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, EECD, eecd);
+	}
+
+	return 0;
+}
+
+#if 0
+static void
+e1000_eeprom_cleanup(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+
+	eecd = E1000_READ_REG(hw, EECD);
+	eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+	E1000_WRITE_REG(hw, EECD, eecd);
+	e1000_raise_ee_clk(hw, &eecd);
+	e1000_lower_ee_clk(hw, &eecd);
+}
+
+static uint16_t
+e1000_wait_eeprom_done(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+	uint32_t i;
+
+	e1000_standby_eeprom(hw);
+	for (i = 0; i < 200; i++) {
+		eecd = E1000_READ_REG(hw, EECD);
+		if (eecd & E1000_EECD_DO)
+			return (TRUE);
+		udelay(5);
+	}
+	return (FALSE);
+}
+
+static int
+e1000_write_eeprom(struct e1000_hw *hw, uint16_t Reg, uint16_t Data)
+{
+	uint32_t eecd;
+	int large_eeprom = FALSE;
+	int i = 0;
+
+	/* Request EEPROM Access */
+	if (hw->mac_type > e1000_82544) {
+		eecd = E1000_READ_REG(hw, EECD);
+		if (eecd & E1000_EECD_SIZE)
+			large_eeprom = TRUE;
+		eecd |= E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, EECD, eecd);
+		eecd = E1000_READ_REG(hw, EECD);
+		while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+			i++;
+			udelay(5);
+			eecd = E1000_READ_REG(hw, EECD);
+		}
+		if (!(eecd & E1000_EECD_GNT)) {
+			eecd &= ~E1000_EECD_REQ;
+			E1000_WRITE_REG(hw, EECD, eecd);
+			DEBUGOUT("Could not acquire EEPROM grant\n");
+			return FALSE;
+		}
+	}
+	e1000_setup_eeprom(hw);
+	e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
+	e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
+	e1000_standby_eeprom(hw);
+	e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
+	e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 8 : 6);
+	e1000_shift_out_ee_bits(hw, Data, 16);
+	if (!e1000_wait_eeprom_done(hw)) {
+		return FALSE;
+	}
+	e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
+	e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
+	e1000_eeprom_cleanup(hw);
+
+	/* Stop requesting EEPROM access */
+	if (hw->mac_type > e1000_82544) {
+		eecd = E1000_READ_REG(hw, EECD);
+		eecd &= ~E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, EECD, eecd);
+	}
+	i = 0;
+	eecd = E1000_READ_REG(hw, EECD);
+	while (((eecd & E1000_EECD_GNT)) && (i < 500)) {
+		i++;
+		udelay(10);
+		eecd = E1000_READ_REG(hw, EECD);
+	}
+	if ((eecd & E1000_EECD_GNT)) {
+		DEBUGOUT("Could not release EEPROM grant\n");
+	}
+	return TRUE;
+}
+#endif
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+static int
+e1000_validate_eeprom_checksum(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint16_t checksum = 0;
+	uint16_t i, eeprom_data;
+
+	DEBUGFUNC();
+
+	for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+		if (e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+			DEBUGOUT("EEPROM Read Error\n");
+			return -E1000_ERR_EEPROM;
+		}
+		checksum += eeprom_data;
+	}
+
+	if (checksum == (uint16_t) EEPROM_SUM) {
+		return 0;
+	} else {
+		DEBUGOUT("EEPROM Checksum Invalid\n");
+		return -E1000_ERR_EEPROM;
+	}
+}
+#endif /* #ifndef CONFIG_AP1000 */
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * nic - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int
+e1000_read_mac_addr(struct eth_device *nic)
+{
+#ifndef CONFIG_AP1000
+	struct e1000_hw *hw = nic->priv;
+	uint16_t offset;
+	uint16_t eeprom_data;
+	int i;
+
+	DEBUGFUNC();
+
+	for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+		offset = i >> 1;
+		if (e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+			DEBUGOUT("EEPROM Read Error\n");
+			return -E1000_ERR_EEPROM;
+		}
+		nic->enetaddr[i] = eeprom_data & 0xff;
+		nic->enetaddr[i + 1] = (eeprom_data >> 8) & 0xff;
+	}
+	if ((hw->mac_type == e1000_82546) &&
+	    (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+		/* Invert the last bit if this is the second device */
+		nic->enetaddr[5] += 1;
+	}
+#else
+	/*
+	 * The AP1000's e1000 has no eeprom; the MAC address is stored in the
+	 * environment variables.  Currently this does not support the addition
+	 * of a PMC e1000 card, which is certainly a possibility, so this should
+	 * be updated to properly use the env variable only for the onboard e1000
+	 */
+
+	int ii;
+	char *s, *e;
+
+	DEBUGFUNC();
+
+	s = getenv ("ethaddr");
+	if (s == NULL){
+		return -E1000_ERR_EEPROM;
+	}
+	else{
+		for(ii = 0; ii < 6; ii++) {
+			nic->enetaddr[ii] = s ? simple_strtoul (s, &e, 16) : 0;
+			if (s){
+				s = (*e) ? e + 1 : e;
+			}
+		}
+	}
+#endif
+	return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+static void
+e1000_init_rx_addrs(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t i;
+	uint32_t addr_low;
+	uint32_t addr_high;
+
+	DEBUGFUNC();
+
+	/* Setup the receive address. */
+	DEBUGOUT("Programming MAC Address into RAR[0]\n");
+	addr_low = (nic->enetaddr[0] |
+		    (nic->enetaddr[1] << 8) |
+		    (nic->enetaddr[2] << 16) | (nic->enetaddr[3] << 24));
+
+	addr_high = (nic->enetaddr[4] | (nic->enetaddr[5] << 8) | E1000_RAH_AV);
+
+	E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+	E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+	/* Zero out the other 15 receive addresses. */
+	DEBUGOUT("Clearing RAR[1-15]\n");
+	for (i = 1; i < E1000_RAR_ENTRIES; i++) {
+		E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+		E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+	}
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+	uint32_t offset;
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+		E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int
+e1000_set_mac_type(struct e1000_hw *hw)
+{
+	DEBUGFUNC();
+
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82542:
+		switch (hw->revision_id) {
+		case E1000_82542_2_0_REV_ID:
+			hw->mac_type = e1000_82542_rev2_0;
+			break;
+		case E1000_82542_2_1_REV_ID:
+			hw->mac_type = e1000_82542_rev2_1;
+			break;
+		default:
+			/* Invalid 82542 revision ID */
+			return -E1000_ERR_MAC_TYPE;
+		}
+		break;
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+		hw->mac_type = e1000_82543;
+		break;
+	case E1000_DEV_ID_82544EI_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82544GC_COPPER:
+	case E1000_DEV_ID_82544GC_LOM:
+		hw->mac_type = e1000_82544;
+		break;
+	case E1000_DEV_ID_82540EM:
+	case E1000_DEV_ID_82540EM_LOM:
+		hw->mac_type = e1000_82540;
+		break;
+	case E1000_DEV_ID_82545EM_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+		hw->mac_type = e1000_82545;
+		break;
+	case E1000_DEV_ID_82546EB_COPPER:
+	case E1000_DEV_ID_82546EB_FIBER:
+		hw->mac_type = e1000_82546;
+		break;
+	default:
+		/* Should never have loaded on this device */
+		return -E1000_ERR_MAC_TYPE;
+	}
+	return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+	uint32_t ctrl;
+	uint32_t ctrl_ext;
+	uint32_t icr;
+	uint32_t manc;
+
+	DEBUGFUNC();
+
+	/* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+	if (hw->mac_type == e1000_82542_rev2_0) {
+		DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+		pci_write_config_word(hw->pdev, PCI_COMMAND,
+				      hw->
+				      pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+	}
+
+	/* Clear interrupt mask to stop board from generating interrupts */
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+	/* Disable the Transmit and Receive units.  Then delay to allow
+	 * any pending transactions to complete before we hit the MAC with
+	 * the global reset.
+	 */
+	E1000_WRITE_REG(hw, RCTL, 0);
+	E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	/* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+	hw->tbi_compatibility_on = FALSE;
+
+	/* Delay to allow any outstanding PCI transactions to complete before
+	 * resetting the device
+	 */
+	mdelay(10);
+
+	/* Issue a global reset to the MAC.  This will reset the chip's
+	 * transmit, receive, DMA, and link units.  It will not effect
+	 * the current PCI configuration.  The global reset bit is self-
+	 * clearing, and should clear within a microsecond.
+	 */
+	DEBUGOUT("Issuing a global reset to MAC\n");
+	ctrl = E1000_READ_REG(hw, CTRL);
+
+#if 0
+	if (hw->mac_type > e1000_82543)
+		E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+	else
+#endif
+		E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+	/* Force a reload from the EEPROM if necessary */
+	if (hw->mac_type < e1000_82540) {
+		/* Wait for reset to complete */
+		udelay(10);
+		ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+		E1000_WRITE_FLUSH(hw);
+		/* Wait for EEPROM reload */
+		mdelay(2);
+	} else {
+		/* Wait for EEPROM reload (it happens automatically) */
+		mdelay(4);
+		/* Dissable HW ARPs on ASF enabled adapters */
+		manc = E1000_READ_REG(hw, MANC);
+		manc &= ~(E1000_MANC_ARP_EN);
+		E1000_WRITE_REG(hw, MANC, manc);
+	}
+
+	/* Clear interrupt mask to stop board from generating interrupts */
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+	/* Clear any pending interrupt events. */
+	icr = E1000_READ_REG(hw, ICR);
+
+	/* If MWI was previously enabled, reenable it. */
+	if (hw->mac_type == e1000_82542_rev2_0) {
+		pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
+	}
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+static int
+e1000_init_hw(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t ctrl, status;
+	uint32_t i;
+	int32_t ret_val;
+	uint16_t pcix_cmd_word;
+	uint16_t pcix_stat_hi_word;
+	uint16_t cmd_mmrbc;
+	uint16_t stat_mmrbc;
+	e1000_bus_type bus_type = e1000_bus_type_unknown;
+
+	DEBUGFUNC();
+#if 0
+	/* Initialize Identification LED */
+	ret_val = e1000_id_led_init(hw);
+	if (ret_val < 0) {
+		DEBUGOUT("Error Initializing Identification LED\n");
+		return ret_val;
+	}
+#endif
+	/* Set the Media Type and exit with error if it is not valid. */
+	if (hw->mac_type != e1000_82543) {
+		/* tbi_compatibility is only valid on 82543 */
+		hw->tbi_compatibility_en = FALSE;
+	}
+
+	if (hw->mac_type >= e1000_82543) {
+		status = E1000_READ_REG(hw, STATUS);
+		if (status & E1000_STATUS_TBIMODE) {
+			hw->media_type = e1000_media_type_fiber;
+			/* tbi_compatibility not valid on fiber */
+			hw->tbi_compatibility_en = FALSE;
+		} else {
+			hw->media_type = e1000_media_type_copper;
+		}
+	} else {
+		/* This is an 82542 (fiber only) */
+		hw->media_type = e1000_media_type_fiber;
+	}
+
+	/* Disabling VLAN filtering. */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	E1000_WRITE_REG(hw, VET, 0);
+
+	e1000_clear_vfta(hw);
+
+	/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+	if (hw->mac_type == e1000_82542_rev2_0) {
+		DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+		pci_write_config_word(hw->pdev, PCI_COMMAND,
+				      hw->
+				      pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+		E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+		E1000_WRITE_FLUSH(hw);
+		mdelay(5);
+	}
+
+	/* Setup the receive address. This involves initializing all of the Receive
+	 * Address Registers (RARs 0 - 15).
+	 */
+	e1000_init_rx_addrs(nic);
+
+	/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+	if (hw->mac_type == e1000_82542_rev2_0) {
+		E1000_WRITE_REG(hw, RCTL, 0);
+		E1000_WRITE_FLUSH(hw);
+		mdelay(1);
+		pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
+	}
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+#if 0
+	/* Set the PCI priority bit correctly in the CTRL register.  This
+	 * determines if the adapter gives priority to receives, or if it
+	 * gives equal priority to transmits and receives.
+	 */
+	if (hw->dma_fairness) {
+		ctrl = E1000_READ_REG(hw, CTRL);
+		E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+	}
+#endif
+	if (hw->mac_type >= e1000_82543) {
+		status = E1000_READ_REG(hw, STATUS);
+		bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+		    e1000_bus_type_pcix : e1000_bus_type_pci;
+	}
+	/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+	if (bus_type == e1000_bus_type_pcix) {
+		pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
+				     &pcix_cmd_word);
+		pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI,
+				     &pcix_stat_hi_word);
+		cmd_mmrbc =
+		    (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+		    PCIX_COMMAND_MMRBC_SHIFT;
+		stat_mmrbc =
+		    (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+		    PCIX_STATUS_HI_MMRBC_SHIFT;
+		if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+			stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+		if (cmd_mmrbc > stat_mmrbc) {
+			pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+			pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+			pci_write_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
+					      pcix_cmd_word);
+		}
+	}
+
+	/* Call a subroutine to configure the link and setup flow control. */
+	ret_val = e1000_setup_link(nic);
+
+	/* Set the transmit descriptor write-back policy */
+	if (hw->mac_type > e1000_82544) {
+		ctrl = E1000_READ_REG(hw, TXDCTL);
+		ctrl =
+		    (ctrl & ~E1000_TXDCTL_WTHRESH) |
+		    E1000_TXDCTL_FULL_TX_DESC_WB;
+		E1000_WRITE_REG(hw, TXDCTL, ctrl);
+	}
+#if 0
+	/* Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs(hw);
+#endif
+
+	return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+static int
+e1000_setup_link(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t ctrl_ext;
+	int32_t ret_val;
+	uint16_t eeprom_data;
+
+	DEBUGFUNC();
+
+#ifndef CONFIG_AP1000
+	/* Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+		DEBUGOUT("EEPROM Read Error\n");
+		return -E1000_ERR_EEPROM;
+	}
+#else
+	/* we have to hardcode the proper value for our hardware. */
+	/* this value is for the 82540EM pci card used for prototyping, and it works. */
+	eeprom_data = 0xb220;
+#endif
+
+	if (hw->fc == e1000_fc_default) {
+		if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+			hw->fc = e1000_fc_none;
+		else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+			 EEPROM_WORD0F_ASM_DIR)
+			hw->fc = e1000_fc_tx_pause;
+		else
+			hw->fc = e1000_fc_full;
+	}
+
+	/* We want to save off the original Flow Control configuration just
+	 * in case we get disconnected and then reconnected into a different
+	 * hub or switch with different Flow Control capabilities.
+	 */
+	if (hw->mac_type == e1000_82542_rev2_0)
+		hw->fc &= (~e1000_fc_tx_pause);
+
+	if ((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+		hw->fc &= (~e1000_fc_rx_pause);
+
+	hw->original_fc = hw->fc;
+
+	DEBUGOUT("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+	/* Take the 4 bits from EEPROM word 0x0F that determine the initial
+	 * polarity value for the SW controlled pins, and setup the
+	 * Extended Device Control reg with that info.
+	 * This is needed because one of the SW controlled pins is used for
+	 * signal detection.  So this should be done before e1000_setup_pcs_link()
+	 * or e1000_phy_setup() is called.
+	 */
+	if (hw->mac_type == e1000_82543) {
+		ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+			    SWDPIO__EXT_SHIFT);
+		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+	}
+
+	/* Call the necessary subroutine to configure the link. */
+	ret_val = (hw->media_type == e1000_media_type_fiber) ?
+	    e1000_setup_fiber_link(nic) : e1000_setup_copper_link(nic);
+	if (ret_val < 0) {
+		return ret_val;
+	}
+
+	/* Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	DEBUGOUT
+	    ("Initializing the Flow Control address, type and timer regs\n");
+
+	E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+	E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+	E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+	/* Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames in not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (!(hw->fc & e1000_fc_tx_pause)) {
+		E1000_WRITE_REG(hw, FCRTL, 0);
+		E1000_WRITE_REG(hw, FCRTH, 0);
+	} else {
+		/* We need to set up the Receive Threshold high and low water marks
+		 * as well as (optionally) enabling the transmission of XON frames.
+		 */
+		if (hw->fc_send_xon) {
+			E1000_WRITE_REG(hw, FCRTL,
+					(hw->fc_low_water | E1000_FCRTL_XONE));
+			E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+		} else {
+			E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+			E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+		}
+	}
+	return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int
+e1000_setup_fiber_link(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t ctrl;
+	uint32_t status;
+	uint32_t txcw = 0;
+	uint32_t i;
+	uint32_t signal;
+	int32_t ret_val;
+
+	DEBUGFUNC();
+	/* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+	 * set when the optics detect a signal. On older adapters, it will be
+	 * cleared when there is a signal
+	 */
+	ctrl = E1000_READ_REG(hw, CTRL);
+	if ((hw->mac_type > e1000_82544) && !(ctrl & E1000_CTRL_ILOS))
+		signal = E1000_CTRL_SWDPIN1;
+	else
+		signal = 0;
+
+	printf("signal for %s is %x (ctrl %08x)!!!!\n", nic->name, signal,
+	       ctrl);
+	/* Take the link out of reset */
+	ctrl &= ~(E1000_CTRL_LRST);
+
+	e1000_config_collision_dist(hw);
+
+	/* Check for a software override of the flow control settings, and setup
+	 * the device accordingly.  If auto-negotiation is enabled, then software
+	 * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+	 * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
+	 * auto-negotiation is disabled, then software will have to manually
+	 * configure the two flow control enable bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames, but
+	 *          not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we do
+	 *          not support receiving pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 */
+	switch (hw->fc) {
+	case e1000_fc_none:
+		/* Flow control is completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/* RX Flow control is enabled and TX Flow control is disabled by a
+		 * software over-ride. Since there really isn't a way to advertise
+		 * that we are capable of RX Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric RX PAUSE. Later, we will
+		 *  disable the adapter's ability to send PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/* TX Flow control is enabled, and RX Flow control is disabled, by a
+		 * software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/* Flow control (both RX and TX) is enabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		return -E1000_ERR_CONFIG;
+		break;
+	}
+
+	/* Since auto-negotiation is enabled, take the link out of reset (the link
+	 * will be in reset, because we previously reset the chip). This will
+	 * restart auto-negotiation.  If auto-neogtiation is successful then the
+	 * link-up status bit will be set and the flow control enable bits (RFCE
+	 * and TFCE) will be set according to their negotiated value.
+	 */
+	DEBUGOUT("Auto-negotiation enabled (%#x)\n", txcw);
+
+	E1000_WRITE_REG(hw, TXCW, txcw);
+	E1000_WRITE_REG(hw, CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	hw->txcw = txcw;
+	mdelay(1);
+
+	/* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+	 * indication in the Device Status Register.  Time-out if a link isn't
+	 * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+	 * less than 500 milliseconds even if the other end is doing it in SW).
+	 */
+	if ((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+		DEBUGOUT("Looking for Link\n");
+		for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+			mdelay(10);
+			status = E1000_READ_REG(hw, STATUS);
+			if (status & E1000_STATUS_LU)
+				break;
+		}
+		if (i == (LINK_UP_TIMEOUT / 10)) {
+			/* AutoNeg failed to achieve a link, so we'll call
+			 * e1000_check_for_link. This routine will force the link up if we
+			 * detect a signal. This will allow us to communicate with
+			 * non-autonegotiating link partners.
+			 */
+			DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+			hw->autoneg_failed = 1;
+			ret_val = e1000_check_for_link(nic);
+			if (ret_val < 0) {
+				DEBUGOUT("Error while checking for link\n");
+				return ret_val;
+			}
+			hw->autoneg_failed = 0;
+		} else {
+			hw->autoneg_failed = 0;
+			DEBUGOUT("Valid Link Found\n");
+		}
+	} else {
+		DEBUGOUT("No Signal Detected\n");
+		return -E1000_ERR_NOLINK;
+	}
+	return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_setup_copper_link(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t ctrl;
+	int32_t ret_val;
+	uint16_t i;
+	uint16_t phy_data;
+
+	DEBUGFUNC();
+
+	ctrl = E1000_READ_REG(hw, CTRL);
+	/* With 82543, we need to force speed and duplex on the MAC equal to what
+	 * the PHY speed and duplex configuration is. In addition, we need to
+	 * perform a hardware reset on the PHY to take it out of reset.
+	 */
+	if (hw->mac_type > e1000_82543) {
+		ctrl |= E1000_CTRL_SLU;
+		ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+		E1000_WRITE_REG(hw, CTRL, ctrl);
+	} else {
+		ctrl |=
+		    (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+		E1000_WRITE_REG(hw, CTRL, ctrl);
+		e1000_phy_hw_reset(hw);
+	}
+
+	/* Make sure we have a valid PHY */
+	ret_val = e1000_detect_gig_phy(hw);
+	if (ret_val < 0) {
+		DEBUGOUT("Error, did not detect valid phy.\n");
+		return ret_val;
+	}
+	DEBUGOUT("Phy ID = %x \n", hw->phy_id);
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+#if 0
+	/* Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	switch (hw->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+#else
+	phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+#endif
+
+#if 0
+	/* Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (hw->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+#else
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+#endif
+	if (e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* Force TX_CLK in the Extended PHY Specific Control Register
+	 * to 25MHz clock.
+	 */
+	if (e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	/* Configure Master and Slave downshift values */
+	phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+		      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+	phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+		     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+	if (e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* SW Reset the PHY so all changes take effect */
+	ret_val = e1000_phy_reset(hw);
+	if (ret_val < 0) {
+		DEBUGOUT("Error Resetting the PHY\n");
+		return ret_val;
+	}
+
+	/* Options:
+	 *   autoneg = 1 (default)
+	 *      PHY will advertise value(s) parsed from
+	 *      autoneg_advertised and fc
+	 *   autoneg = 0
+	 *      PHY will be set to 10H, 10F, 100H, or 100F
+	 *      depending on value parsed from forced_speed_duplex.
+	 */
+
+	/* Is autoneg enabled?  This is enabled by default or by software override.
+	 * If so, call e1000_phy_setup_autoneg routine to parse the
+	 * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+	 * user should have provided a speed/duplex override.  If so, then call
+	 * e1000_phy_force_speed_duplex to parse and set this up.
+	 */
+	/* Perform some bounds checking on the hw->autoneg_advertised
+	 * parameter.  If this variable is zero, then set it to the default.
+	 */
+	hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+	/* If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (hw->autoneg_advertised == 0)
+		hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+	ret_val = e1000_phy_setup_autoneg(hw);
+	if (ret_val < 0) {
+		DEBUGOUT("Error Setting up Auto-Negotiation\n");
+		return ret_val;
+	}
+	DEBUGOUT("Restarting Auto-Neg\n");
+
+	/* Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+#if 0
+	/* Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (hw->wait_autoneg_complete) {
+		ret_val = e1000_wait_autoneg(hw);
+		if (ret_val < 0) {
+			DEBUGOUT
+			    ("Error while waiting for autoneg to complete\n");
+			return ret_val;
+		}
+	}
+#else
+	/* If we do not wait for autonegtation to complete I
+	 * do not see a valid link status.
+	 */
+	ret_val = e1000_wait_autoneg(hw);
+	if (ret_val < 0) {
+		DEBUGOUT("Error while waiting for autoneg to complete\n");
+		return ret_val;
+	}
+#endif
+
+	/* Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	for (i = 0; i < 10; i++) {
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+		if (phy_data & MII_SR_LINK_STATUS) {
+			/* We have link, so we need to finish the config process:
+			 *   1) Set up the MAC to the current PHY speed/duplex
+			 *      if we are on 82543.  If we
+			 *      are on newer silicon, we only need to configure
+			 *      collision distance in the Transmit Control Register.
+			 *   2) Set up flow control on the MAC to that established with
+			 *      the link partner.
+			 */
+			if (hw->mac_type >= e1000_82544) {
+				e1000_config_collision_dist(hw);
+			} else {
+				ret_val = e1000_config_mac_to_phy(hw);
+				if (ret_val < 0) {
+					DEBUGOUT
+					    ("Error configuring MAC to PHY settings\n");
+					return ret_val;
+				}
+			}
+			ret_val = e1000_config_fc_after_link_up(hw);
+			if (ret_val < 0) {
+				DEBUGOUT("Error Configuring Flow Control\n");
+				return ret_val;
+			}
+			DEBUGOUT("Valid link established!!!\n");
+			return 0;
+		}
+		udelay(10);
+	}
+
+	DEBUGOUT("Unable to establish link!!!\n");
+	return -E1000_ERR_NOLINK;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	uint16_t mii_autoneg_adv_reg;
+	uint16_t mii_1000t_ctrl_reg;
+
+	DEBUGFUNC();
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	if (e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* Read the MII 1000Base-T Control Register (Address 9). */
+	if (e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/* First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+	mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+	DEBUGOUT("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (hw->autoneg_advertised & ADVERTISE_10_HALF) {
+		DEBUGOUT("Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (hw->autoneg_advertised & ADVERTISE_10_FULL) {
+		DEBUGOUT("Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (hw->autoneg_advertised & ADVERTISE_100_HALF) {
+		DEBUGOUT("Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (hw->autoneg_advertised & ADVERTISE_100_FULL) {
+		DEBUGOUT("Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+		DEBUGOUT
+		    ("Advertise 1000mb Half duplex requested, request denied!\n");
+	}
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+		DEBUGOUT("Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/* Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc) {
+	case e1000_fc_none:	/* 0 */
+		/* Flow control (RX & TX) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:	/* 1 */
+		/* RX Flow control is enabled, and TX Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		/* Since there really isn't a way to advertise that we are
+		 * capable of RX Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric RX PAUSE.  Later
+		 * (in e1000_config_fc_after_link_up) we will disable the
+		 *hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:	/* 2 */
+		/* TX Flow control is enabled, and RX Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:	/* 3 */
+		/* Flow control (both RX and TX) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	if (e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+
+	DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+	return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+static void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+	uint32_t tctl;
+
+	tctl = E1000_READ_REG(hw, TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	E1000_WRITE_REG(hw, TCTL, tctl);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+	uint32_t ctrl;
+	uint16_t phy_data;
+
+	DEBUGFUNC();
+
+	/* Read the Device Control Register and set the bits to Force Speed
+	 * and Duplex.
+	 */
+	ctrl = E1000_READ_REG(hw, CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+	/* Set up duplex in the Device Control and Transmit Control
+	 * registers depending on negotiated values.
+	 */
+	if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	if (phy_data & M88E1000_PSSR_DPLX)
+		ctrl |= E1000_CTRL_FD;
+	else
+		ctrl &= ~E1000_CTRL_FD;
+
+	e1000_config_collision_dist(hw);
+
+	/* Set up speed in the Device Control register depending on
+	 * negotiated values.
+	 */
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+		ctrl |= E1000_CTRL_SPD_1000;
+	else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+		ctrl |= E1000_CTRL_SPD_100;
+	/* Write the configured values back to the Device Control Reg. */
+	E1000_WRITE_REG(hw, CTRL, ctrl);
+	return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+	uint32_t ctrl;
+
+	DEBUGFUNC();
+
+	/* Get the current configuration of the Device Control Register */
+	ctrl = E1000_READ_REG(hw, CTRL);
+
+	/* Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+
+	switch (hw->fc) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	/* Disable TX Flow Control for 82542 (rev 2.0) */
+	if (hw->mac_type == e1000_82542_rev2_0)
+		ctrl &= (~E1000_CTRL_TFCE);
+
+	E1000_WRITE_REG(hw, CTRL, ctrl);
+	return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+static int
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+	int32_t ret_val;
+	uint16_t mii_status_reg;
+	uint16_t mii_nway_adv_reg;
+	uint16_t mii_nway_lp_ability_reg;
+	uint16_t speed;
+	uint16_t duplex;
+
+	DEBUGFUNC();
+
+	/* Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if ((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) {
+		ret_val = e1000_force_mac_fc(hw);
+		if (ret_val < 0) {
+			DEBUGOUT("Error forcing flow control settings\n");
+			return ret_val;
+		}
+	}
+
+	/* Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if (hw->media_type == e1000_media_type_copper) {
+		/* Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+			DEBUGOUT("PHY Read Error \n");
+			return -E1000_ERR_PHY;
+		}
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+			DEBUGOUT("PHY Read Error \n");
+			return -E1000_ERR_PHY;
+		}
+
+		if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+			/* The AutoNeg process has completed, so we now need to
+			 * read both the Auto Negotiation Advertisement Register
+			 * (Address 4) and the Auto_Negotiation Base Page Ability
+			 * Register (Address 5) to determine how flow control was
+			 * negotiated.
+			 */
+			if (e1000_read_phy_reg
+			    (hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+				DEBUGOUT("PHY Read Error\n");
+				return -E1000_ERR_PHY;
+			}
+			if (e1000_read_phy_reg
+			    (hw, PHY_LP_ABILITY,
+			     &mii_nway_lp_ability_reg) < 0) {
+				DEBUGOUT("PHY Read Error\n");
+				return -E1000_ERR_PHY;
+			}
+
+			/* Two bits in the Auto Negotiation Advertisement Register
+			 * (Address 4) and two bits in the Auto Negotiation Base
+			 * Page Ability Register (Address 5) determine flow control
+			 * for both the PHY and the link partner.  The following
+			 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+			 * 1999, describes these PAUSE resolution bits and how flow
+			 * control is determined based upon these settings.
+			 * NOTE:  DC = Don't Care
+			 *
+			 *   LOCAL DEVICE  |   LINK PARTNER
+			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+			 *-------|---------|-------|---------|--------------------
+			 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+			 *   0   |    1    |   0   |   DC    | e1000_fc_none
+			 *   0   |    1    |   1   |    0    | e1000_fc_none
+			 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+			 *   1   |    0    |   0   |   DC    | e1000_fc_none
+			 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+			 *   1   |    1    |   0   |    0    | e1000_fc_none
+			 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+			 *
+			 */
+			/* Are both PAUSE bits set to 1?  If so, this implies
+			 * Symmetric Flow Control is enabled at both ends.  The
+			 * ASM_DIR bits are irrelevant per the spec.
+			 *
+			 * For Symmetric Flow Control:
+			 *
+			 *   LOCAL DEVICE  |   LINK PARTNER
+			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+			 *-------|---------|-------|---------|--------------------
+			 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+			 *
+			 */
+			if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+			    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+				/* Now we need to check if the user selected RX ONLY
+				 * of pause frames.  In this case, we had to advertise
+				 * FULL flow control because we could not advertise RX
+				 * ONLY. Hence, we must now check to see if we need to
+				 * turn OFF  the TRANSMISSION of PAUSE frames.
+				 */
+				if (hw->original_fc == e1000_fc_full) {
+					hw->fc = e1000_fc_full;
+					DEBUGOUT("Flow Control = FULL.\r\n");
+				} else {
+					hw->fc = e1000_fc_rx_pause;
+					DEBUGOUT
+					    ("Flow Control = RX PAUSE frames only.\r\n");
+				}
+			}
+			/* For receiving PAUSE frames ONLY.
+			 *
+			 *   LOCAL DEVICE  |   LINK PARTNER
+			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+			 *-------|---------|-------|---------|--------------------
+			 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+			 *
+			 */
+			else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+				 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+				 (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
+			{
+				hw->fc = e1000_fc_tx_pause;
+				DEBUGOUT
+				    ("Flow Control = TX PAUSE frames only.\r\n");
+			}
+			/* For transmitting PAUSE frames ONLY.
+			 *
+			 *   LOCAL DEVICE  |   LINK PARTNER
+			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+			 *-------|---------|-------|---------|--------------------
+			 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+			 *
+			 */
+			else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+				 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+				 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+				 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
+			{
+				hw->fc = e1000_fc_rx_pause;
+				DEBUGOUT
+				    ("Flow Control = RX PAUSE frames only.\r\n");
+			}
+			/* Per the IEEE spec, at this point flow control should be
+			 * disabled.  However, we want to consider that we could
+			 * be connected to a legacy switch that doesn't advertise
+			 * desired flow control, but can be forced on the link
+			 * partner.  So if we advertised no flow control, that is
+			 * what we will resolve to.  If we advertised some kind of
+			 * receive capability (Rx Pause Only or Full Flow Control)
+			 * and the link partner advertised none, we will configure
+			 * ourselves to enable Rx Flow Control only.  We can do
+			 * this safely for two reasons:  If the link partner really
+			 * didn't want flow control enabled, and we enable Rx, no
+			 * harm done since we won't be receiving any PAUSE frames
+			 * anyway.  If the intent on the link partner was to have
+			 * flow control enabled, then by us enabling RX only, we
+			 * can at least receive pause frames and process them.
+			 * This is a good idea because in most cases, since we are
+			 * predominantly a server NIC, more times than not we will
+			 * be asked to delay transmission of packets than asking
+			 * our link partner to pause transmission of frames.
+			 */
+			else if (hw->original_fc == e1000_fc_none ||
+				 hw->original_fc == e1000_fc_tx_pause) {
+				hw->fc = e1000_fc_none;
+				DEBUGOUT("Flow Control = NONE.\r\n");
+			} else {
+				hw->fc = e1000_fc_rx_pause;
+				DEBUGOUT
+				    ("Flow Control = RX PAUSE frames only.\r\n");
+			}
+
+			/* Now we need to do one last check...  If we auto-
+			 * negotiated to HALF DUPLEX, flow control should not be
+			 * enabled per IEEE 802.3 spec.
+			 */
+			e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+			if (duplex == HALF_DUPLEX)
+				hw->fc = e1000_fc_none;
+
+			/* Now we call a subroutine to actually force the MAC
+			 * controller to use the correct flow control settings.
+			 */
+			ret_val = e1000_force_mac_fc(hw);
+			if (ret_val < 0) {
+				DEBUGOUT
+				    ("Error forcing flow control settings\n");
+				return ret_val;
+			}
+		} else {
+			DEBUGOUT
+			    ("Copper PHY and Auto Neg has not completed.\r\n");
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+static int
+e1000_check_for_link(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	uint32_t rxcw;
+	uint32_t ctrl;
+	uint32_t status;
+	uint32_t rctl;
+	uint32_t signal;
+	int32_t ret_val;
+	uint16_t phy_data;
+	uint16_t lp_capability;
+
+	DEBUGFUNC();
+
+	/* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+	 * set when the optics detect a signal. On older adapters, it will be
+	 * cleared when there is a signal
+	 */
+	ctrl = E1000_READ_REG(hw, CTRL);
+	if ((hw->mac_type > e1000_82544) && !(ctrl & E1000_CTRL_ILOS))
+		signal = E1000_CTRL_SWDPIN1;
+	else
+		signal = 0;
+
+	status = E1000_READ_REG(hw, STATUS);
+	rxcw = E1000_READ_REG(hw, RXCW);
+	DEBUGOUT("ctrl: %#08x status %#08x rxcw %#08x\n", ctrl, status, rxcw);
+
+	/* If we have a copper PHY then we only want to go out to the PHY
+	 * registers to see if Auto-Neg has completed and/or if our link
+	 * status has changed.  The get_link_status flag will be set if we
+	 * receive a Link Status Change interrupt or we have Rx Sequence
+	 * Errors.
+	 */
+	if ((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+		/* First we want to see if the MII Status Register reports
+		 * link.  If so, then we want to get the current speed/duplex
+		 * of the PHY.
+		 * Read the register twice since the link bit is sticky.
+		 */
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+
+		if (phy_data & MII_SR_LINK_STATUS) {
+			hw->get_link_status = FALSE;
+		} else {
+			/* No link detected */
+			return -E1000_ERR_NOLINK;
+		}
+
+		/* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+		 * have Si on board that is 82544 or newer, Auto
+		 * Speed Detection takes care of MAC speed/duplex
+		 * configuration.  So we only need to configure Collision
+		 * Distance in the MAC.  Otherwise, we need to force
+		 * speed/duplex on the MAC to the current PHY speed/duplex
+		 * settings.
+		 */
+		if (hw->mac_type >= e1000_82544)
+			e1000_config_collision_dist(hw);
+		else {
+			ret_val = e1000_config_mac_to_phy(hw);
+			if (ret_val < 0) {
+				DEBUGOUT
+				    ("Error configuring MAC to PHY settings\n");
+				return ret_val;
+			}
+		}
+
+		/* Configure Flow Control now that Auto-Neg has completed. First, we
+		 * need to restore the desired flow control settings because we may
+		 * have had to re-autoneg with a different link partner.
+		 */
+		ret_val = e1000_config_fc_after_link_up(hw);
+		if (ret_val < 0) {
+			DEBUGOUT("Error configuring flow control\n");
+			return ret_val;
+		}
+
+		/* At this point we know that we are on copper and we have
+		 * auto-negotiated link.  These are conditions for checking the link
+		 * parter capability register.  We use the link partner capability to
+		 * determine if TBI Compatibility needs to be turned on or off.  If
+		 * the link partner advertises any speed in addition to Gigabit, then
+		 * we assume that they are GMII-based, and TBI compatibility is not
+		 * needed. If no other speeds are advertised, we assume the link
+		 * partner is TBI-based, and we turn on TBI Compatibility.
+		 */
+		if (hw->tbi_compatibility_en) {
+			if (e1000_read_phy_reg
+			    (hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+				DEBUGOUT("PHY Read Error\n");
+				return -E1000_ERR_PHY;
+			}
+			if (lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+					     NWAY_LPAR_10T_FD_CAPS |
+					     NWAY_LPAR_100TX_HD_CAPS |
+					     NWAY_LPAR_100TX_FD_CAPS |
+					     NWAY_LPAR_100T4_CAPS)) {
+				/* If our link partner advertises anything in addition to
+				 * gigabit, we do not need to enable TBI compatibility.
+				 */
+				if (hw->tbi_compatibility_on) {
+					/* If we previously were in the mode, turn it off. */
+					rctl = E1000_READ_REG(hw, RCTL);
+					rctl &= ~E1000_RCTL_SBP;
+					E1000_WRITE_REG(hw, RCTL, rctl);
+					hw->tbi_compatibility_on = FALSE;
+				}
+			} else {
+				/* If TBI compatibility is was previously off, turn it on. For
+				 * compatibility with a TBI link partner, we will store bad
+				 * packets. Some frames have an additional byte on the end and
+				 * will look like CRC errors to to the hardware.
+				 */
+				if (!hw->tbi_compatibility_on) {
+					hw->tbi_compatibility_on = TRUE;
+					rctl = E1000_READ_REG(hw, RCTL);
+					rctl |= E1000_RCTL_SBP;
+					E1000_WRITE_REG(hw, RCTL, rctl);
+				}
+			}
+		}
+	}
+	/* If we don't have link (auto-negotiation failed or link partner cannot
+	 * auto-negotiate), the cable is plugged in (we have signal), and our
+	 * link partner is not trying to auto-negotiate with us (we are receiving
+	 * idles or data), we need to force link up. We also need to give
+	 * auto-negotiation time to complete, in case the cable was just plugged
+	 * in. The autoneg_failed flag does this.
+	 */
+	else if ((hw->media_type == e1000_media_type_fiber) &&
+		 (!(status & E1000_STATUS_LU)) &&
+		 ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+		 (!(rxcw & E1000_RXCW_C))) {
+		if (hw->autoneg_failed == 0) {
+			hw->autoneg_failed = 1;
+			return 0;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up(hw);
+		if (ret_val < 0) {
+			DEBUGOUT("Error configuring flow control\n");
+			return ret_val;
+		}
+	}
+	/* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+	 * auto-negotiation in the TXCW register and disable forced link in the
+	 * Device Control register in an attempt to auto-negotiate with our link
+	 * partner.
+	 */
+	else if ((hw->media_type == e1000_media_type_fiber) &&
+		 (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		DEBUGOUT
+		    ("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+		E1000_WRITE_REG(hw, TXCW, hw->txcw);
+		E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+	}
+	return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+static void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+			   uint16_t * speed, uint16_t * duplex)
+{
+	uint32_t status;
+
+	DEBUGFUNC();
+
+	if (hw->mac_type >= e1000_82543) {
+		status = E1000_READ_REG(hw, STATUS);
+		if (status & E1000_STATUS_SPEED_1000) {
+			*speed = SPEED_1000;
+			DEBUGOUT("1000 Mbs, ");
+		} else if (status & E1000_STATUS_SPEED_100) {
+			*speed = SPEED_100;
+			DEBUGOUT("100 Mbs, ");
+		} else {
+			*speed = SPEED_10;
+			DEBUGOUT("10 Mbs, ");
+		}
+
+		if (status & E1000_STATUS_FD) {
+			*duplex = FULL_DUPLEX;
+			DEBUGOUT("Full Duplex\r\n");
+		} else {
+			*duplex = HALF_DUPLEX;
+			DEBUGOUT(" Half Duplex\r\n");
+		}
+	} else {
+		DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+		*speed = SPEED_1000;
+		*duplex = FULL_DUPLEX;
+	}
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+	uint16_t i;
+	uint16_t phy_data;
+
+	DEBUGFUNC();
+	DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+	/* We will wait for autoneg to complete or 4.5 seconds to expire. */
+	for (i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+		/* Read the MII Status Register and wait for Auto-Neg
+		 * Complete bit to be set.
+		 */
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+		if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+			DEBUGOUT("PHY Read Error\n");
+			return -E1000_ERR_PHY;
+		}
+		if (phy_data & MII_SR_AUTONEG_COMPLETE) {
+			DEBUGOUT("Auto-Neg complete.\n");
+			return 0;
+		}
+		mdelay(100);
+	}
+	DEBUGOUT("Auto-Neg timedout.\n");
+	return -E1000_ERR_TIMEOUT;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t * ctrl)
+{
+	/* Raise the clock input to the Management Data Clock (by setting the MDC
+	 * bit), and then delay 2 microseconds.
+	 */
+	E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+	E1000_WRITE_FLUSH(hw);
+	udelay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t * ctrl)
+{
+	/* Lower the clock input to the Management Data Clock (by clearing the MDC
+	 * bit), and then delay 2 microseconds.
+	 */
+	E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+	E1000_WRITE_FLUSH(hw);
+	udelay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count)
+{
+	uint32_t ctrl;
+	uint32_t mask;
+
+	/* We need to shift "count" number of bits out to the PHY. So, the value
+	 * in the "data" parameter will be shifted out to the PHY one bit at a
+	 * time. In order to do this, "data" must be broken down into bits.
+	 */
+	mask = 0x01;
+	mask <<= (count - 1);
+
+	ctrl = E1000_READ_REG(hw, CTRL);
+
+	/* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+	ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+	while (mask) {
+		/* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+		 * then raising and lowering the Management Data Clock. A "0" is
+		 * shifted out to the PHY by setting the MDIO bit to "0" and then
+		 * raising and lowering the clock.
+		 */
+		if (data & mask)
+			ctrl |= E1000_CTRL_MDIO;
+		else
+			ctrl &= ~E1000_CTRL_MDIO;
+
+		E1000_WRITE_REG(hw, CTRL, ctrl);
+		E1000_WRITE_FLUSH(hw);
+
+		udelay(2);
+
+		e1000_raise_mdi_clk(hw, &ctrl);
+		e1000_lower_mdi_clk(hw, &ctrl);
+
+		mask = mask >> 1;
+	}
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+	uint32_t ctrl;
+	uint16_t data = 0;
+	uint8_t i;
+
+	/* In order to read a register from the PHY, we need to shift in a total
+	 * of 18 bits from the PHY. The first two bit (turnaround) times are used
+	 * to avoid contention on the MDIO pin when a read operation is performed.
+	 * These two bits are ignored by us and thrown away. Bits are "shifted in"
+	 * by raising the input to the Management Data Clock (setting the MDC bit),
+	 * and then reading the value of the MDIO bit.
+	 */
+	ctrl = E1000_READ_REG(hw, CTRL);
+
+	/* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+	ctrl &= ~E1000_CTRL_MDIO_DIR;
+	ctrl &= ~E1000_CTRL_MDIO;
+
+	E1000_WRITE_REG(hw, CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	/* Raise and Lower the clock before reading in the data. This accounts for
+	 * the turnaround bits. The first clock occurred when we clocked out the
+	 * last bit of the Register Address.
+	 */
+	e1000_raise_mdi_clk(hw, &ctrl);
+	e1000_lower_mdi_clk(hw, &ctrl);
+
+	for (data = 0, i = 0; i < 16; i++) {
+		data = data << 1;
+		e1000_raise_mdi_clk(hw, &ctrl);
+		ctrl = E1000_READ_REG(hw, CTRL);
+		/* Check to see if we shifted in a "1". */
+		if (ctrl & E1000_CTRL_MDIO)
+			data |= 1;
+		e1000_lower_mdi_clk(hw, &ctrl);
+	}
+
+	e1000_raise_mdi_clk(hw, &ctrl);
+	e1000_lower_mdi_clk(hw, &ctrl);
+
+	return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+static int
+e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t * phy_data)
+{
+	uint32_t i;
+	uint32_t mdic = 0;
+	const uint32_t phy_addr = 1;
+
+	if (reg_addr > MAX_PHY_REG_ADDRESS) {
+		DEBUGOUT("PHY Address %d is out of range\n", reg_addr);
+		return -E1000_ERR_PARAM;
+	}
+
+	if (hw->mac_type > e1000_82543) {
+		/* Set up Op-code, Phy Address, and register address in the MDI
+		 * Control register.  The MAC will take care of interfacing with the
+		 * PHY to retrieve the desired data.
+		 */
+		mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+			(phy_addr << E1000_MDIC_PHY_SHIFT) |
+			(E1000_MDIC_OP_READ));
+
+		E1000_WRITE_REG(hw, MDIC, mdic);
+
+		/* Poll the ready bit to see if the MDI read completed */
+		for (i = 0; i < 64; i++) {
+			udelay(10);
+			mdic = E1000_READ_REG(hw, MDIC);
+			if (mdic & E1000_MDIC_READY)
+				break;
+		}
+		if (!(mdic & E1000_MDIC_READY)) {
+			DEBUGOUT("MDI Read did not complete\n");
+			return -E1000_ERR_PHY;
+		}
+		if (mdic & E1000_MDIC_ERROR) {
+			DEBUGOUT("MDI Error\n");
+			return -E1000_ERR_PHY;
+		}
+		*phy_data = (uint16_t) mdic;
+	} else {
+		/* We must first send a preamble through the MDIO pin to signal the
+		 * beginning of an MII instruction.  This is done by sending 32
+		 * consecutive "1" bits.
+		 */
+		e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+		/* Now combine the next few fields that are required for a read
+		 * operation.  We use this method instead of calling the
+		 * e1000_shift_out_mdi_bits routine five different times. The format of
+		 * a MII read instruction consists of a shift out of 14 bits and is
+		 * defined as follows:
+		 *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+		 * followed by a shift in of 18 bits.  This first two bits shifted in
+		 * are TurnAround bits used to avoid contention on the MDIO pin when a
+		 * READ operation is performed.  These two bits are thrown away
+		 * followed by a shift in of 16 bits which contains the desired data.
+		 */
+		mdic = ((reg_addr) | (phy_addr << 5) |
+			(PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+		e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+		/* Now that we've shifted out the read command to the MII, we need to
+		 * "shift in" the 16-bit value (18 total bits) of the requested PHY
+		 * register address.
+		 */
+		*phy_data = e1000_shift_in_mdi_bits(hw);
+	}
+	return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+static int
+e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data)
+{
+	uint32_t i;
+	uint32_t mdic = 0;
+	const uint32_t phy_addr = 1;
+
+	if (reg_addr > MAX_PHY_REG_ADDRESS) {
+		DEBUGOUT("PHY Address %d is out of range\n", reg_addr);
+		return -E1000_ERR_PARAM;
+	}
+
+	if (hw->mac_type > e1000_82543) {
+		/* Set up Op-code, Phy Address, register address, and data intended
+		 * for the PHY register in the MDI Control register.  The MAC will take
+		 * care of interfacing with the PHY to send the desired data.
+		 */
+		mdic = (((uint32_t) phy_data) |
+			(reg_addr << E1000_MDIC_REG_SHIFT) |
+			(phy_addr << E1000_MDIC_PHY_SHIFT) |
+			(E1000_MDIC_OP_WRITE));
+
+		E1000_WRITE_REG(hw, MDIC, mdic);
+
+		/* Poll the ready bit to see if the MDI read completed */
+		for (i = 0; i < 64; i++) {
+			udelay(10);
+			mdic = E1000_READ_REG(hw, MDIC);
+			if (mdic & E1000_MDIC_READY)
+				break;
+		}
+		if (!(mdic & E1000_MDIC_READY)) {
+			DEBUGOUT("MDI Write did not complete\n");
+			return -E1000_ERR_PHY;
+		}
+	} else {
+		/* We'll need to use the SW defined pins to shift the write command
+		 * out to the PHY. We first send a preamble to the PHY to signal the
+		 * beginning of the MII instruction.  This is done by sending 32
+		 * consecutive "1" bits.
+		 */
+		e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+		/* Now combine the remaining required fields that will indicate a
+		 * write operation. We use this method instead of calling the
+		 * e1000_shift_out_mdi_bits routine for each field in the command. The
+		 * format of a MII write instruction is as follows:
+		 * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+		 */
+		mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+			(PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+		mdic <<= 16;
+		mdic |= (uint32_t) phy_data;
+
+		e1000_shift_out_mdi_bits(hw, mdic, 32);
+	}
+	return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+	uint32_t ctrl;
+	uint32_t ctrl_ext;
+
+	DEBUGFUNC();
+
+	DEBUGOUT("Resetting Phy...\n");
+
+	if (hw->mac_type > e1000_82543) {
+		/* Read the device control register and assert the E1000_CTRL_PHY_RST
+		 * bit. Then, take it out of reset.
+		 */
+		ctrl = E1000_READ_REG(hw, CTRL);
+		E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+		E1000_WRITE_FLUSH(hw);
+		mdelay(10);
+		E1000_WRITE_REG(hw, CTRL, ctrl);
+		E1000_WRITE_FLUSH(hw);
+	} else {
+		/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+		 * bit to put the PHY into reset. Then, take it out of reset.
+		 */
+		ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+		ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+		ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+		E1000_WRITE_FLUSH(hw);
+		mdelay(10);
+		ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+		E1000_WRITE_FLUSH(hw);
+	}
+	udelay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+static int
+e1000_phy_reset(struct e1000_hw *hw)
+{
+	uint16_t phy_data;
+
+	DEBUGFUNC();
+
+	if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	phy_data |= MII_CR_RESET;
+	if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+		DEBUGOUT("PHY Write Error\n");
+		return -E1000_ERR_PHY;
+	}
+	udelay(1);
+	return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+	uint16_t phy_id_high, phy_id_low;
+	int match = FALSE;
+
+	DEBUGFUNC();
+
+	/* Read the PHY ID Registers to identify which PHY is onboard. */
+	if (e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	hw->phy_id = (uint32_t) (phy_id_high << 16);
+	udelay(2);
+	if (e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+		DEBUGOUT("PHY Read Error\n");
+		return -E1000_ERR_PHY;
+	}
+	hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+
+	switch (hw->mac_type) {
+	case e1000_82543:
+		if (hw->phy_id == M88E1000_E_PHY_ID)
+			match = TRUE;
+		break;
+	case e1000_82544:
+		if (hw->phy_id == M88E1000_I_PHY_ID)
+			match = TRUE;
+		break;
+	case e1000_82540:
+	case e1000_82545:
+	case e1000_82546:
+		if (hw->phy_id == M88E1011_I_PHY_ID)
+			match = TRUE;
+		break;
+	default:
+		DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
+		return -E1000_ERR_CONFIG;
+	}
+	if (match) {
+		DEBUGOUT("PHY ID 0x%X detected\n", hw->phy_id);
+		return 0;
+	}
+	DEBUGOUT("Invalid PHY ID 0x%X\n", hw->phy_id);
+	return -E1000_ERR_PHY;
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+
+static int
+e1000_sw_init(struct eth_device *nic, int cardnum)
+{
+	struct e1000_hw *hw = (typeof(hw)) nic->priv;
+	int result;
+
+	/* PCI config space info */
+	pci_read_config_word(hw->pdev, PCI_VENDOR_ID, &hw->vendor_id);
+	pci_read_config_word(hw->pdev, PCI_DEVICE_ID, &hw->device_id);
+	pci_read_config_word(hw->pdev, PCI_SUBSYSTEM_VENDOR_ID,
+			     &hw->subsystem_vendor_id);
+	pci_read_config_word(hw->pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_id);
+
+	pci_read_config_byte(hw->pdev, PCI_REVISION_ID, &hw->revision_id);
+	pci_read_config_word(hw->pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+	/* identify the MAC */
+	result = e1000_set_mac_type(hw);
+	if (result) {
+		E1000_ERR("Unknown MAC Type\n");
+		return result;
+	}
+
+	/* lan a vs. lan b settings */
+	if (hw->mac_type == e1000_82546)
+		/*this also works w/ multiple 82546 cards */
+		/*but not if they're intermingled /w other e1000s */
+		hw->lan_loc = (cardnum % 2) ? e1000_lan_b : e1000_lan_a;
+	else
+		hw->lan_loc = e1000_lan_a;
+
+	/* flow control settings */
+	hw->fc_high_water = E1000_FC_HIGH_THRESH;
+	hw->fc_low_water = E1000_FC_LOW_THRESH;
+	hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+	hw->fc_send_xon = 1;
+
+	/* Media type - copper or fiber */
+
+	if (hw->mac_type >= e1000_82543) {
+		uint32_t status = E1000_READ_REG(hw, STATUS);
+
+		if (status & E1000_STATUS_TBIMODE) {
+			DEBUGOUT("fiber interface\n");
+			hw->media_type = e1000_media_type_fiber;
+		} else {
+			DEBUGOUT("copper interface\n");
+			hw->media_type = e1000_media_type_copper;
+		}
+	} else {
+		hw->media_type = e1000_media_type_fiber;
+	}
+
+	if (hw->mac_type < e1000_82543)
+		hw->report_tx_early = 0;
+	else
+		hw->report_tx_early = 1;
+
+	hw->tbi_compatibility_en = TRUE;
+#if 0
+	hw->wait_autoneg_complete = FALSE;
+	hw->adaptive_ifs = TRUE;
+
+	/* Copper options */
+	if (hw->media_type == e1000_media_type_copper) {
+		hw->mdix = AUTO_ALL_MODES;
+		hw->disable_polarity_correction = FALSE;
+	}
+#endif
+	return E1000_SUCCESS;
+}
+
+void
+fill_rx(struct e1000_hw *hw)
+{
+	struct e1000_rx_desc *rd;
+
+	rx_last = rx_tail;
+	rd = rx_base + rx_tail;
+	rx_tail = (rx_tail + 1) % 8;
+	memset(rd, 0, 16);
+	rd->buffer_addr = cpu_to_le64((u32) & packet);
+	E1000_WRITE_REG(hw, RDT, rx_tail);
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_tx(struct e1000_hw *hw)
+{
+	unsigned long ptr;
+	unsigned long tctl;
+	unsigned long tipg;
+
+	ptr = (u32) tx_pool;
+	if (ptr & 0xf)
+		ptr = (ptr + 0x10) & (~0xf);
+
+	tx_base = (typeof(tx_base)) ptr;
+
+	E1000_WRITE_REG(hw, TDBAL, (u32) tx_base);
+	E1000_WRITE_REG(hw, TDBAH, 0);
+
+	E1000_WRITE_REG(hw, TDLEN, 128);
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	E1000_WRITE_REG(hw, TDH, 0);
+	E1000_WRITE_REG(hw, TDT, 0);
+	tx_tail = 0;
+
+	/* Set the default values for the Tx Inter Packet Gap timer */
+	switch (hw->mac_type) {
+	case e1000_82542_rev2_0:
+	case e1000_82542_rev2_1:
+		tipg = DEFAULT_82542_TIPG_IPGT;
+		tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+		tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+		break;
+	default:
+		if (hw->media_type == e1000_media_type_fiber)
+			tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+		else
+			tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+		tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+		tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+	}
+	E1000_WRITE_REG(hw, TIPG, tipg);
+#if 0
+	/* Set the Tx Interrupt Delay register */
+	E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
+	if (hw->mac_type >= e1000_82540)
+		E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay);
+#endif
+	/* Program the Transmit Control Register */
+	tctl = E1000_READ_REG(hw, TCTL);
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+	    (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+	E1000_WRITE_REG(hw, TCTL, tctl);
+
+	e1000_config_collision_dist(hw);
+#if 0
+	/* Setup Transmit Descriptor Settings for this adapter */
+	adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+
+	if (adapter->hw.report_tx_early == 1)
+		adapter->txd_cmd |= E1000_TXD_CMD_RS;
+	else
+		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
+#endif
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control register
+ * @adapter: Board private structure
+ **/
+static void
+e1000_setup_rctl(struct e1000_hw *hw)
+{
+	uint32_t rctl;
+
+	rctl = E1000_READ_REG(hw, RCTL);
+
+	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF;	/* |
+												   (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
+
+	if (hw->tbi_compatibility_on == 1)
+		rctl |= E1000_RCTL_SBP;
+	else
+		rctl &= ~E1000_RCTL_SBP;
+
+	rctl &= ~(E1000_RCTL_SZ_4096);
+#if 0
+	switch (adapter->rx_buffer_len) {
+	case E1000_RXBUFFER_2048:
+	default:
+#endif
+		rctl |= E1000_RCTL_SZ_2048;
+		rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
+#if 0
+		break;
+	case E1000_RXBUFFER_4096:
+		rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	case E1000_RXBUFFER_8192:
+		rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	case E1000_RXBUFFER_16384:
+		rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	}
+#endif
+	E1000_WRITE_REG(hw, RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void
+e1000_configure_rx(struct e1000_hw *hw)
+{
+	unsigned long ptr;
+	unsigned long rctl;
+#if 0
+	unsigned long rxcsum;
+#endif
+	rx_tail = 0;
+	/* make sure receives are disabled while setting up the descriptors */
+	rctl = E1000_READ_REG(hw, RCTL);
+	E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
+#if 0
+	/* set the Receive Delay Timer Register */
+
+	E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay);
+#endif
+	if (hw->mac_type >= e1000_82540) {
+#if 0
+		E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay);
+#endif
+		/* Set the interrupt throttling rate.  Value is calculated
+		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC        8000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+		E1000_WRITE_REG(hw, ITR, DEFAULT_ITR);
+	}
+
+	/* Setup the Base and Length of the Rx Descriptor Ring */
+	ptr = (u32) rx_pool;
+	if (ptr & 0xf)
+		ptr = (ptr + 0x10) & (~0xf);
+	rx_base = (typeof(rx_base)) ptr;
+	E1000_WRITE_REG(hw, RDBAL, (u32) rx_base);
+	E1000_WRITE_REG(hw, RDBAH, 0);
+
+	E1000_WRITE_REG(hw, RDLEN, 128);
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers */
+	E1000_WRITE_REG(hw, RDH, 0);
+	E1000_WRITE_REG(hw, RDT, 0);
+#if 0
+	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
+	if ((adapter->hw.mac_type >= e1000_82543) && (adapter->rx_csum == TRUE)) {
+		rxcsum = E1000_READ_REG(hw, RXCSUM);
+		rxcsum |= E1000_RXCSUM_TUOFL;
+		E1000_WRITE_REG(hw, RXCSUM, rxcsum);
+	}
+#endif
+	/* Enable Receives */
+
+	E1000_WRITE_REG(hw, RCTL, rctl);
+	fill_rx(hw);
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int
+e1000_poll(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+	struct e1000_rx_desc *rd;
+	/* return true if there's an ethernet packet ready to read */
+	rd = rx_base + rx_last;
+	if (!(le32_to_cpu(rd->status)) & E1000_RXD_STAT_DD)
+		return 0;
+	/*DEBUGOUT("recv: packet len=%d \n", rd->length); */
+	NetReceive((uchar *)packet, le32_to_cpu(rd->length));
+	fill_rx(hw);
+	return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static int
+e1000_transmit(struct eth_device *nic, volatile void *packet, int length)
+{
+	struct e1000_hw *hw = nic->priv;
+	struct e1000_tx_desc *txp;
+	int i = 0;
+
+	txp = tx_base + tx_tail;
+	tx_tail = (tx_tail + 1) % 8;
+
+	txp->buffer_addr = cpu_to_le64(virt_to_bus(packet));
+	txp->lower.data = cpu_to_le32(E1000_TXD_CMD_RPS | E1000_TXD_CMD_EOP |
+				      E1000_TXD_CMD_IFCS | length);
+	txp->upper.data = 0;
+	E1000_WRITE_REG(hw, TDT, tx_tail);
+
+	while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
+		if (i++ > TOUT_LOOP) {
+			DEBUGOUT("e1000: tx timeout\n");
+			return 0;
+		}
+		udelay(10);	/* give the nic a chance to write to the register */
+	}
+	return 1;
+}
+
+/*reset function*/
+static inline int
+e1000_reset(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+
+	e1000_reset_hw(hw);
+	if (hw->mac_type >= e1000_82544) {
+		E1000_WRITE_REG(hw, WUC, 0);
+	}
+	return e1000_init_hw(nic);
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void
+e1000_disable(struct eth_device *nic)
+{
+	struct e1000_hw *hw = nic->priv;
+
+	/* Turn off the ethernet interface */
+	E1000_WRITE_REG(hw, RCTL, 0);
+	E1000_WRITE_REG(hw, TCTL, 0);
+
+	/* Clear the transmit ring */
+	E1000_WRITE_REG(hw, TDH, 0);
+	E1000_WRITE_REG(hw, TDT, 0);
+
+	/* Clear the receive ring */
+	E1000_WRITE_REG(hw, RDH, 0);
+	E1000_WRITE_REG(hw, RDT, 0);
+
+	/* put the card in its initial state */
+#if 0
+	E1000_WRITE_REG(hw, CTRL, E1000_CTRL_RST);
+#endif
+	mdelay(10);
+
+}
+
+/**************************************************************************
+INIT - set up ethernet interface(s)
+***************************************************************************/
+static int
+e1000_init(struct eth_device *nic, bd_t * bis)
+{
+	struct e1000_hw *hw = nic->priv;
+	int ret_val = 0;
+
+	ret_val = e1000_reset(nic);
+	if (ret_val < 0) {
+		if ((ret_val == -E1000_ERR_NOLINK) ||
+		    (ret_val == -E1000_ERR_TIMEOUT)) {
+			E1000_ERR("Valid Link not detected\n");
+		} else {
+			E1000_ERR("Hardware Initialization Failed\n");
+		}
+		return 0;
+	}
+	e1000_configure_tx(hw);
+	e1000_setup_rctl(hw);
+	e1000_configure_rx(hw);
+	return 1;
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+You should omit the last argument struct pci_device * for a non-PCI NIC
+***************************************************************************/
+int
+e1000_initialize(bd_t * bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *nic = NULL;
+	struct e1000_hw *hw = NULL;
+	u32 iobase;
+	int idx = 0;
+	u32 PciCommandWord;
+
+	while (1) {		/* Find PCI device(s) */
+		if ((devno = pci_find_devices(supported, idx++)) < 0) {
+			break;
+		}
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
+		iobase &= ~0xf;	/* Mask the bits that say "this is an io addr" */
+		DEBUGOUT("e1000#%d: iobase 0x%08x\n", card_number, iobase);
+
+		pci_write_config_dword(devno, PCI_COMMAND,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+		/* Check if I/O accesses and Bus Mastering are enabled. */
+		pci_read_config_dword(devno, PCI_COMMAND, &PciCommandWord);
+		if (!(PciCommandWord & PCI_COMMAND_MEMORY)) {
+			printf("Error: Can not enable MEM access.\n");
+			continue;
+		} else if (!(PciCommandWord & PCI_COMMAND_MASTER)) {
+			printf("Error: Can not enable Bus Mastering.\n");
+			continue;
+		}
+
+		nic = (struct eth_device *) malloc(sizeof (*nic));
+		hw = (struct e1000_hw *) malloc(sizeof (*hw));
+		hw->pdev = devno;
+		nic->priv = hw;
+		nic->iobase = bus_to_phys(devno, iobase);
+
+		sprintf(nic->name, "e1000#%d", card_number);
+
+		/* Are these variables needed? */
+#if 0
+		hw->fc = e1000_fc_none;
+		hw->original_fc = e1000_fc_none;
+#else
+		hw->fc = e1000_fc_default;
+		hw->original_fc = e1000_fc_default;
+#endif
+		hw->autoneg_failed = 0;
+		hw->get_link_status = TRUE;
+		hw->hw_addr = (typeof(hw->hw_addr)) iobase;
+		hw->mac_type = e1000_undefined;
+
+		/* MAC and Phy settings */
+		if (e1000_sw_init(nic, card_number) < 0) {
+			free(hw);
+			free(nic);
+			return 0;
+		}
+#ifndef CONFIG_AP1000
+		if (e1000_validate_eeprom_checksum(nic) < 0) {
+			printf("The EEPROM Checksum Is Not Valid\n");
+			free(hw);
+			free(nic);
+			return 0;
+		}
+#endif
+		e1000_read_mac_addr(nic);
+
+		E1000_WRITE_REG(hw, PBA, E1000_DEFAULT_PBA);
+
+		printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
+		       nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]);
+
+		nic->init = e1000_init;
+		nic->recv = e1000_poll;
+		nic->send = e1000_transmit;
+		nic->halt = e1000_disable;
+
+		eth_register(nic);
+
+		card_number++;
+	}
+	return 1;
+}
+
+#endif
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
new file mode 100644
index 0000000..0fbdc90
--- /dev/null
+++ b/drivers/net/e1000.h
@@ -0,0 +1,1758 @@
+/*******************************************************************************
+
+
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+
+  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.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define E1000_ERR(args...) printf("e1000: " args)
+
+#ifdef E1000_DEBUG
+#define E1000_DBG(args...)	printf("e1000: " args)
+#define DEBUGOUT(fmt,args...) printf(fmt ,##args)
+#define DEBUGFUNC()        printf("%s\n", __FUNCTION__);
+#else
+#define E1000_DBG(args...)
+#define DEBUGFUNC()
+#define DEBUGOUT(fmt,args...)
+#endif
+
+/* Forward declarations of structures used by the shared code */
+struct e1000_hw;
+struct e1000_hw_stats;
+
+typedef enum {
+	FALSE = 0,
+	TRUE = 1
+} boolean_t;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+	e1000_undefined = 0,
+	e1000_82542_rev2_0,
+	e1000_82542_rev2_1,
+	e1000_82543,
+	e1000_82544,
+	e1000_82540,
+	e1000_82545,
+	e1000_82546,
+	e1000_num_macs
+} e1000_mac_type;
+
+/* Media Types */
+typedef enum {
+	e1000_media_type_copper = 0,
+	e1000_media_type_fiber = 1,
+	e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+	e1000_10_half = 0,
+	e1000_10_full = 1,
+	e1000_100_half = 2,
+	e1000_100_full = 3
+} e1000_speed_duplex_type;
+
+typedef enum {
+	e1000_lan_a = 0,
+	e1000_lan_b = 1
+} e1000_lan_loc;
+
+/* Flow Control Settings */
+typedef enum {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause = 1,
+	e1000_fc_tx_pause = 2,
+	e1000_fc_full = 3,
+	e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+/* PCI bus types */
+typedef enum {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix
+} e1000_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_133,
+	e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_32,
+	e1000_bus_width_64
+} e1000_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+	e1000_cable_length_50 = 0,
+	e1000_cable_length_50_80,
+	e1000_cable_length_80_110,
+	e1000_cable_length_110_140,
+	e1000_cable_length_140,
+	e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+
+typedef enum {
+	e1000_10bt_ext_dist_enable_normal = 0,
+	e1000_10bt_ext_dist_enable_lower,
+	e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
+
+typedef enum {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+	e1000_polarity_reversal_enabled = 0,
+	e1000_polarity_reversal_disabled,
+	e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+	e1000_auto_x_mode_manual_mdi = 0,
+	e1000_auto_x_mode_manual_mdix,
+	e1000_auto_x_mode_auto1,
+	e1000_auto_x_mode_auto2,
+	e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+	e1000_cable_length cable_length;
+	e1000_10bt_ext_dist_enable extended_10bt_distance;
+	e1000_rev_polarity cable_polarity;
+	e1000_polarity_reversal polarity_correction;
+	e1000_auto_x_mode mdix_mode;
+	e1000_1000t_rx_status local_rx;
+	e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+	uint32_t idle_errors;
+	uint32_t receive_errors;
+};
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_NOLINK   6
+#define E1000_ERR_TIMEOUT  7
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542          0x1000
+#define E1000_DEV_ID_82543GC_FIBER  0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER  0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM    0x100D
+#define E1000_DEV_ID_82540EM        0x100E
+#define E1000_DEV_ID_82540EM_LOM    0x1015
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER  0x1011
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER  0x1012
+#define NUM_DEV_IDS 13
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518	/* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64	/* With FCS */
+#define ETHERNET_FCS_SIZE            4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH                   ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE         0x3F00
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE                     4	/* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100	/* 802.3ac packet */
+#define ETHERNET_IP_TYPE        0x0800	/* IP packets */
+#define ETHERNET_ARP_TYPE       0x0806	/* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP    6
+#define IP_PROTOCOL_UDP    0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |         \
+    E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* The number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 16
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
+	uint16_t length;	/* Length of data DMAed into data buffer */
+	uint16_t csum;		/* Packet checksum */
+	uint8_t status;		/* Descriptor status */
+	uint8_t errors;		/* Descriptor Errors */
+	uint16_t special;
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01	/* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02	/* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04	/* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08	/* IEEE VLAN Packet */
+#define E1000_RXD_STAT_TCPCS    0x20	/* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40	/* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80	/* passed in-exact filter */
+#define E1000_RXD_ERR_CE        0x01	/* CRC Error */
+#define E1000_RXD_ERR_SE        0x02	/* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04	/* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10	/* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20	/* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40	/* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80	/* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF	/* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000	/* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 0x000D	/* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_CFI_MASK  0x1000	/* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 0x000C	/* CFI is bit 12 */
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
+	union {
+		uint32_t data;
+		struct {
+			uint16_t length;	/* Data buffer length */
+			uint8_t cso;	/* Checksum offset */
+			uint8_t cmd;	/* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		uint32_t data;
+		struct {
+			uint8_t status;	/* Descriptor status */
+			uint8_t css;	/* Checksum start */
+			uint16_t special;
+		} fields;
+	} upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000	/* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000	/* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01	/* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02	/* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000	/* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000	/* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000	/* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000	/* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000	/* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000	/* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000	/* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000	/* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001	/* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002	/* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004	/* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008	/* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000	/* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000	/* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000	/* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004	/* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		uint32_t ip_config;
+		struct {
+			uint8_t ipcss;	/* IP checksum start */
+			uint8_t ipcso;	/* IP checksum offset */
+			uint16_t ipcse;	/* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		uint32_t tcp_config;
+		struct {
+			uint8_t tucss;	/* TCP checksum start */
+			uint8_t tucso;	/* TCP checksum offset */
+			uint16_t tucse;	/* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	uint32_t cmd_and_length;	/* */
+	union {
+		uint32_t data;
+		struct {
+			uint8_t status;	/* Descriptor status */
+			uint8_t hdr_len;	/* Header length */
+			uint16_t mss;	/* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	uint64_t buffer_addr;	/* Address of the descriptor's buffer address */
+	union {
+		uint32_t data;
+		struct {
+			uint16_t length;	/* Data buffer length */
+			uint8_t typ_len_ext;	/* */
+			uint8_t cmd;	/* */
+		} flags;
+	} lower;
+	union {
+		uint32_t data;
+		struct {
+			uint8_t status;	/* Descriptor status */
+			uint8_t popts;	/* Packet Options */
+			uint16_t special;	/* */
+		} fields;
+	} upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16	/* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128	/* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128	/* VLAN Filter Table (4096 bits) */
+
+/* Receive Address Register */
+struct e1000_rar {
+	volatile uint32_t low;	/* receive address low */
+	volatile uint32_t high;	/* receive address high */
+};
+
+/* The number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct e1000_ipv4_at_entry {
+	volatile uint32_t ipv4_addr;	/* IP Address (RW) */
+	volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE                  1
+
+/* IPv6 Address Table Entry */
+struct e1000_ipv6_at_entry {
+	volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct e1000_fflt_entry {
+	volatile uint32_t length;	/* Flexible Filter Length (RW) */
+	volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct e1000_ffmt_entry {
+	volatile uint32_t mask;	/* Flexible Filter Mask (RW) */
+	volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct e1000_ffvt_entry {
+	volatile uint32_t value;	/* Flexible Filter Value (RW) */
+	volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000	/* Device Control - RW */
+#define E1000_STATUS   0x00008	/* Device Status - RO */
+#define E1000_EECD     0x00010	/* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014	/* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018	/* Extended Device Control - RW */
+#define E1000_MDIC     0x00020	/* MDI Control - RW */
+#define E1000_FCAL     0x00028	/* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C	/* Flow Control Address High -RW */
+#define E1000_FCT      0x00030	/* Flow Control Type - RW */
+#define E1000_VET      0x00038	/* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0	/* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4	/* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8	/* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0	/* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8	/* Interrupt Mask Clear - WO */
+#define E1000_RCTL     0x00100	/* RX Control - RW */
+#define E1000_FCTTV    0x00170	/* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178	/* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180	/* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400	/* TX Control - RW */
+#define E1000_TIPG     0x00410	/* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448	/* TX Burst Timer - RW */
+#define E1000_AIT      0x00458	/* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00	/* LED Control - RW */
+#define E1000_PBA      0x01000	/* Packet Buffer Allocation - RW */
+#define E1000_FCRTL    0x02160	/* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168	/* Flow Control Receive Threshold High - RW */
+#define E1000_RDBAL    0x02800	/* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804	/* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808	/* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810	/* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818	/* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820	/* RX Delay Timer - RW */
+#define E1000_RXDCTL   0x02828	/* RX Descriptor Control - RW */
+#define E1000_RADV     0x0282C	/* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00	/* RX Small Packet Detect - RW */
+#define E1000_TXDMAC   0x03000	/* TX DMA Control - RW */
+#define E1000_TDBAL    0x03800	/* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804	/* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808	/* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810	/* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818	/* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820	/* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828	/* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C	/* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830	/* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000	/* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004	/* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008	/* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C	/* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010	/* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014	/* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018	/* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C	/* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020	/* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028	/* Collision Count - R/clr */
+#define E1000_DC       0x04030	/* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034	/* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038	/* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C	/* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040	/* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048	/* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C	/* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050	/* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054	/* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058	/* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C	/* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060	/* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064	/* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068	/* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C	/* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070	/* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074	/* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078	/* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C	/* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080	/* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088	/* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C	/* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090	/* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094	/* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0	/* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4	/* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8	/* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC	/* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0	/* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4	/* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8	/* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC	/* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0	/* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4	/* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8	/* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC	/* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0	/* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4	/* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8	/* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC	/* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0	/* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4	/* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8	/* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC	/* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0	/* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4	/* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8	/* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC	/* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_RXCSUM   0x05000	/* RX Checksum Control - RW */
+#define E1000_MTA      0x05200	/* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400	/* Receive Address - RW Array */
+#define E1000_VFTA     0x05600	/* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800	/* Wakeup Control - RW */
+#define E1000_WUFC     0x05808	/* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810	/* Wakeup Status - RO */
+#define E1000_MANC     0x05820	/* Management Control - RW */
+#define E1000_IPAV     0x05838	/* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840	/* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880	/* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900	/* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00	/* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00	/* Flexible Filter Length Table - RW Array */
+#define E1000_FFMT     0x09000	/* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800	/* Flexible Filter Value Table - RW Array */
+
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_STATUS   E1000_STATUS
+#define E1000_82542_EECD     E1000_EECD
+#define E1000_82542_EERD     E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_FCAL     E1000_FCAL
+#define E1000_82542_FCAH     E1000_FCAH
+#define E1000_82542_FCT      E1000_FCT
+#define E1000_82542_VET      E1000_VET
+#define E1000_82542_RA       0x00040
+#define E1000_82542_ICR      E1000_ICR
+#define E1000_82542_ITR      E1000_ITR
+#define E1000_82542_ICS      E1000_ICS
+#define E1000_82542_IMS      E1000_IMS
+#define E1000_82542_IMC      E1000_IMC
+#define E1000_82542_RCTL     E1000_RCTL
+#define E1000_82542_RDTR     0x00108
+#define E1000_82542_RDBAL    0x00110
+#define E1000_82542_RDBAH    0x00114
+#define E1000_82542_RDLEN    0x00118
+#define E1000_82542_RDH      0x00120
+#define E1000_82542_RDT      0x00128
+#define E1000_82542_FCRTH    0x00160
+#define E1000_82542_FCRTL    0x00168
+#define E1000_82542_FCTTV    E1000_FCTTV
+#define E1000_82542_TXCW     E1000_TXCW
+#define E1000_82542_RXCW     E1000_RXCW
+#define E1000_82542_MTA      0x00200
+#define E1000_82542_TCTL     E1000_TCTL
+#define E1000_82542_TIPG     E1000_TIPG
+#define E1000_82542_TDBAL    0x00420
+#define E1000_82542_TDBAH    0x00424
+#define E1000_82542_TDLEN    0x00428
+#define E1000_82542_TDH      0x00430
+#define E1000_82542_TDT      0x00438
+#define E1000_82542_TIDV     0x00440
+#define E1000_82542_TBT      E1000_TBT
+#define E1000_82542_AIT      E1000_AIT
+#define E1000_82542_VFTA     0x00600
+#define E1000_82542_LEDCTL   E1000_LEDCTL
+#define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RADV     E1000_RADV
+#define E1000_82542_RSRPD    E1000_RSRPD
+#define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TXDCTL   E1000_TXDCTL
+#define E1000_82542_TADV     E1000_TADV
+#define E1000_82542_TSPMT    E1000_TSPMT
+#define E1000_82542_CRCERRS  E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS  E1000_SYMERRS
+#define E1000_82542_RXERRC   E1000_RXERRC
+#define E1000_82542_MPC      E1000_MPC
+#define E1000_82542_SCC      E1000_SCC
+#define E1000_82542_ECOL     E1000_ECOL
+#define E1000_82542_MCC      E1000_MCC
+#define E1000_82542_LATECOL  E1000_LATECOL
+#define E1000_82542_COLC     E1000_COLC
+#define E1000_82542_DC       E1000_DC
+#define E1000_82542_TNCRS    E1000_TNCRS
+#define E1000_82542_SEC      E1000_SEC
+#define E1000_82542_CEXTERR  E1000_CEXTERR
+#define E1000_82542_RLEC     E1000_RLEC
+#define E1000_82542_XONRXC   E1000_XONRXC
+#define E1000_82542_XONTXC   E1000_XONTXC
+#define E1000_82542_XOFFRXC  E1000_XOFFRXC
+#define E1000_82542_XOFFTXC  E1000_XOFFTXC
+#define E1000_82542_FCRUC    E1000_FCRUC
+#define E1000_82542_PRC64    E1000_PRC64
+#define E1000_82542_PRC127   E1000_PRC127
+#define E1000_82542_PRC255   E1000_PRC255
+#define E1000_82542_PRC511   E1000_PRC511
+#define E1000_82542_PRC1023  E1000_PRC1023
+#define E1000_82542_PRC1522  E1000_PRC1522
+#define E1000_82542_GPRC     E1000_GPRC
+#define E1000_82542_BPRC     E1000_BPRC
+#define E1000_82542_MPRC     E1000_MPRC
+#define E1000_82542_GPTC     E1000_GPTC
+#define E1000_82542_GORCL    E1000_GORCL
+#define E1000_82542_GORCH    E1000_GORCH
+#define E1000_82542_GOTCL    E1000_GOTCL
+#define E1000_82542_GOTCH    E1000_GOTCH
+#define E1000_82542_RNBC     E1000_RNBC
+#define E1000_82542_RUC      E1000_RUC
+#define E1000_82542_RFC      E1000_RFC
+#define E1000_82542_ROC      E1000_ROC
+#define E1000_82542_RJC      E1000_RJC
+#define E1000_82542_MGTPRC   E1000_MGTPRC
+#define E1000_82542_MGTPDC   E1000_MGTPDC
+#define E1000_82542_MGTPTC   E1000_MGTPTC
+#define E1000_82542_TORL     E1000_TORL
+#define E1000_82542_TORH     E1000_TORH
+#define E1000_82542_TOTL     E1000_TOTL
+#define E1000_82542_TOTH     E1000_TOTH
+#define E1000_82542_TPR      E1000_TPR
+#define E1000_82542_TPT      E1000_TPT
+#define E1000_82542_PTC64    E1000_PTC64
+#define E1000_82542_PTC127   E1000_PTC127
+#define E1000_82542_PTC255   E1000_PTC255
+#define E1000_82542_PTC511   E1000_PTC511
+#define E1000_82542_PTC1023  E1000_PTC1023
+#define E1000_82542_PTC1522  E1000_PTC1522
+#define E1000_82542_MPTC     E1000_MPTC
+#define E1000_82542_BPTC     E1000_BPTC
+#define E1000_82542_TSCTC    E1000_TSCTC
+#define E1000_82542_TSCTFC   E1000_TSCTFC
+#define E1000_82542_RXCSUM   E1000_RXCSUM
+#define E1000_82542_WUC      E1000_WUC
+#define E1000_82542_WUFC     E1000_WUFC
+#define E1000_82542_WUS      E1000_WUS
+#define E1000_82542_MANC     E1000_MANC
+#define E1000_82542_IPAV     E1000_IPAV
+#define E1000_82542_IP4AT    E1000_IP4AT
+#define E1000_82542_IP6AT    E1000_IP6AT
+#define E1000_82542_WUPL     E1000_WUPL
+#define E1000_82542_WUPM     E1000_WUPM
+#define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_FFMT     E1000_FFMT
+#define E1000_82542_FFVT     E1000_FFVT
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	uint64_t crcerrs;
+	uint64_t algnerrc;
+	uint64_t symerrs;
+	uint64_t rxerrc;
+	uint64_t mpc;
+	uint64_t scc;
+	uint64_t ecol;
+	uint64_t mcc;
+	uint64_t latecol;
+	uint64_t colc;
+	uint64_t dc;
+	uint64_t tncrs;
+	uint64_t sec;
+	uint64_t cexterr;
+	uint64_t rlec;
+	uint64_t xonrxc;
+	uint64_t xontxc;
+	uint64_t xoffrxc;
+	uint64_t xofftxc;
+	uint64_t fcruc;
+	uint64_t prc64;
+	uint64_t prc127;
+	uint64_t prc255;
+	uint64_t prc511;
+	uint64_t prc1023;
+	uint64_t prc1522;
+	uint64_t gprc;
+	uint64_t bprc;
+	uint64_t mprc;
+	uint64_t gptc;
+	uint64_t gorcl;
+	uint64_t gorch;
+	uint64_t gotcl;
+	uint64_t gotch;
+	uint64_t rnbc;
+	uint64_t ruc;
+	uint64_t rfc;
+	uint64_t roc;
+	uint64_t rjc;
+	uint64_t mgprc;
+	uint64_t mgpdc;
+	uint64_t mgptc;
+	uint64_t torl;
+	uint64_t torh;
+	uint64_t totl;
+	uint64_t toth;
+	uint64_t tpr;
+	uint64_t tpt;
+	uint64_t ptc64;
+	uint64_t ptc127;
+	uint64_t ptc255;
+	uint64_t ptc511;
+	uint64_t ptc1023;
+	uint64_t ptc1522;
+	uint64_t mptc;
+	uint64_t bptc;
+	uint64_t tsctc;
+	uint64_t tsctfc;
+};
+
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
+	pci_dev_t pdev;
+	uint8_t *hw_addr;
+	e1000_mac_type mac_type;
+	e1000_media_type media_type;
+	e1000_lan_loc lan_loc;
+	e1000_fc_type fc;
+#if 0
+	e1000_bus_speed bus_speed;
+	e1000_bus_width bus_width;
+	e1000_bus_type bus_type;
+	uint32_t io_base;
+#endif
+	uint32_t phy_id;
+	uint32_t phy_addr;
+	uint32_t original_fc;
+	uint32_t txcw;
+	uint32_t autoneg_failed;
+#if 0
+	uint32_t max_frame_size;
+	uint32_t min_frame_size;
+	uint32_t mc_filter_type;
+	uint32_t num_mc_addrs;
+	uint32_t collision_delta;
+	uint32_t tx_packet_delta;
+	uint32_t ledctl_default;
+	uint32_t ledctl_mode1;
+	uint32_t ledctl_mode2;
+#endif
+	uint16_t autoneg_advertised;
+	uint16_t pci_cmd_word;
+	uint16_t fc_high_water;
+	uint16_t fc_low_water;
+	uint16_t fc_pause_time;
+#if 0
+	uint16_t current_ifs_val;
+	uint16_t ifs_min_val;
+	uint16_t ifs_max_val;
+	uint16_t ifs_step_size;
+	uint16_t ifs_ratio;
+#endif
+	uint16_t device_id;
+	uint16_t vendor_id;
+	uint16_t subsystem_id;
+	uint16_t subsystem_vendor_id;
+	uint8_t revision_id;
+#if 0
+	uint8_t autoneg;
+	uint8_t mdix;
+	uint8_t forced_speed_duplex;
+	uint8_t wait_autoneg_complete;
+	uint8_t dma_fairness;
+#endif
+#if 0
+	uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+	boolean_t disable_polarity_correction;
+#endif
+	boolean_t get_link_status;
+	boolean_t tbi_compatibility_en;
+	boolean_t tbi_compatibility_on;
+	boolean_t fc_send_xon;
+	boolean_t report_tx_early;
+#if 0
+	boolean_t adaptive_ifs;
+	boolean_t ifs_params_forced;
+	boolean_t in_ifs_mode;
+#endif
+};
+
+#define E1000_EEPROM_SWDPIN0   0x0001	/* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020	/* Led Logic Word */
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001	/* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002	/* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004	/* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008	/* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010	/* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020	/* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020	/* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040	/* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080	/* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300	/* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000	/* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100	/* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200	/* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400	/* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800	/* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000	/* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000	/* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000	/* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000	/* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000	/* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000	/* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000	/* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000	/* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000	/* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000	/* Global reset */
+#define E1000_CTRL_RFCE     0x08000000	/* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000	/* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000	/* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000	/* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000	/* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001	/* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002	/* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C	/* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000	/* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004	/* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010	/* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020	/* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000	/* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040	/* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080	/* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300	/* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400	/* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800	/* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000	/* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000	/* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000	/* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000	/* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000	/* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000	/* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001	/* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002	/* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004	/* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008	/* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010	/* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020	/* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_SIZE      0x00000200	/* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_REQ       0x00000040	/* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080	/* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100	/* EEPROM Present */
+
+/* EEPROM Read */
+#define E1000_EERD_START      0x00000001	/* Start Read */
+#define E1000_EERD_DONE       0x00000010	/* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK  0x0000FF00	/* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK  0xFFFF0000	/* Read Data */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001	/* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002	/* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004	/* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008	/* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010	/* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020	/* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040	/* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SWDPIN6 	 0x00000040	/* SWDPIN 6 value */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080	/* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SWDPIN7 	 0x00000080	/* SWDPIN 7 value */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100	/* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200	/* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400	/* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SWDPIO6   0x00000400	/* SWDPIN 6 Input or output */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800	/* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_SWDPIO7   0x00000800	/* SWDPIN 7 Input or output */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000	/* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000	/* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000	/* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000	/* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK  0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT       0x00000040
+#define E1000_LEDCTL_LED0_BLINK      0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK  0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_IVRT       0x00004000
+#define E1000_LEDCTL_LED1_BLINK      0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK  0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_IVRT       0x00400000
+#define E1000_LEDCTL_LED2_BLINK      0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK  0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT       0x40000000
+#define E1000_LEDCTL_LED3_BLINK      0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000	/* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW    0x00000001	/* Transmit desc written back */
+#define E1000_ICR_TXQE    0x00000002	/* Transmit Queue empty */
+#define E1000_ICR_LSC     0x00000004	/* Link Status Change */
+#define E1000_ICR_RXSEQ   0x00000008	/* rx sequence error */
+#define E1000_ICR_RXDMT0  0x00000010	/* rx desc min. threshold (0) */
+#define E1000_ICR_RXO     0x00000040	/* rx overrun */
+#define E1000_ICR_RXT0    0x00000080	/* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC    0x00000200	/* MDIO access complete */
+#define E1000_ICR_RXCFG   0x00000400	/* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800	/* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000	/* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000	/* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000	/* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD    0x00010000
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW    E1000_ICR_TXDW	/* Transmit desc written back */
+#define E1000_ICS_TXQE    E1000_ICR_TXQE	/* Transmit Queue empty */
+#define E1000_ICS_LSC     E1000_ICR_LSC	/* Link Status Change */
+#define E1000_ICS_RXSEQ   E1000_ICR_RXSEQ	/* rx sequence error */
+#define E1000_ICS_RXDMT0  E1000_ICR_RXDMT0	/* rx desc min. threshold */
+#define E1000_ICS_RXO     E1000_ICR_RXO	/* rx overrun */
+#define E1000_ICS_RXT0    E1000_ICR_RXT0	/* rx timer intr */
+#define E1000_ICS_MDAC    E1000_ICR_MDAC	/* MDIO access complete */
+#define E1000_ICS_RXCFG   E1000_ICR_RXCFG	/* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0	/* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1	/* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2	/* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3	/* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW    E1000_ICR_TXDW	/* Transmit desc written back */
+#define E1000_IMS_TXQE    E1000_ICR_TXQE	/* Transmit Queue empty */
+#define E1000_IMS_LSC     E1000_ICR_LSC	/* Link Status Change */
+#define E1000_IMS_RXSEQ   E1000_ICR_RXSEQ	/* rx sequence error */
+#define E1000_IMS_RXDMT0  E1000_ICR_RXDMT0	/* rx desc min. threshold */
+#define E1000_IMS_RXO     E1000_ICR_RXO	/* rx overrun */
+#define E1000_IMS_RXT0    E1000_ICR_RXT0	/* rx timer intr */
+#define E1000_IMS_MDAC    E1000_ICR_MDAC	/* MDIO access complete */
+#define E1000_IMS_RXCFG   E1000_ICR_RXCFG	/* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0	/* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1	/* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2	/* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3	/* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW    E1000_ICR_TXDW	/* Transmit desc written back */
+#define E1000_IMC_TXQE    E1000_ICR_TXQE	/* Transmit Queue empty */
+#define E1000_IMC_LSC     E1000_ICR_LSC	/* Link Status Change */
+#define E1000_IMC_RXSEQ   E1000_ICR_RXSEQ	/* rx sequence error */
+#define E1000_IMC_RXDMT0  E1000_ICR_RXDMT0	/* rx desc min. threshold */
+#define E1000_IMC_RXO     E1000_ICR_RXO	/* rx overrun */
+#define E1000_IMC_RXT0    E1000_ICR_RXT0	/* rx timer intr */
+#define E1000_IMC_MDAC    E1000_ICR_MDAC	/* MDIO access complete */
+#define E1000_IMC_RXCFG   E1000_ICR_RXCFG	/* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0	/* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1	/* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2	/* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3	/* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD    E1000_ICR_SRPD
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001	/* Software reset */
+#define E1000_RCTL_EN           0x00000002	/* enable */
+#define E1000_RCTL_SBP          0x00000004	/* store bad packet */
+#define E1000_RCTL_UPE          0x00000008	/* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010	/* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020	/* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000	/* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040	/* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080	/* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0	/* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF   0x00000000	/* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100	/* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200	/* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12	/* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000	/* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000	/* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000	/* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000	/* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000	/* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000	/* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000	/* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000	/* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000	/* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000	/* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000	/* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000	/* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000	/* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000	/* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000	/* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000	/* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000	/* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000	/* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000	/* Buffer size extension */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff	/* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB  0x80000000	/* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80	/* descriptor length */
+#define E1000_RDH_RDH   0x0000ffff	/* receive descriptor head */
+#define E1000_RDT_RDT   0x0000ffff	/* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8	/* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000	/* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8	/* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000	/* Enable XON frame transmission */
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F	/* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00	/* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000	/* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN    0x01000000	/* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF	/* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00	/* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000	/* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000	/* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000	/* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000	/* GRAN=1, WTHRESH=1 */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020	/* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040	/* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080	/* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100	/* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180	/* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000	/* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000	/* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff	/* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000	/* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000	/* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW    0x0000ffff	/* RxConfigWord mask */
+#define E1000_RXCW_NC    0x04000000	/* Receive config no carrier */
+#define E1000_RXCW_IV    0x08000000	/* Receive config invalid */
+#define E1000_RXCW_CC    0x10000000	/* Receive config change */
+#define E1000_RXCW_C     0x20000000	/* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000	/* Receive config synch */
+#define E1000_RXCW_ANC   0x80000000	/* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001	/* software reset */
+#define E1000_TCTL_EN     0x00000002	/* enable tx */
+#define E1000_TCTL_BCE    0x00000004	/* busy check enable */
+#define E1000_TCTL_PSP    0x00000008	/* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0	/* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000	/* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000	/* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000	/* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000	/* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000	/* No Re-transmit on underrun */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF	/* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100	/* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200	/* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400	/* IPv6 checksum offload */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001	/* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002	/* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004	/* PME Status */
+#define E1000_WUC_APMPME     0x00000008	/* Assert PME on APM Wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001	/* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002	/* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004	/* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008	/* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010	/* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020	/* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040	/* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080	/* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000	/* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000	/* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000	/* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000	/* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF	/* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16	/* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000	/* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001	/* Link Status Changed */
+#define E1000_WUS_MAG  0x00000002	/* Magic Packet Received */
+#define E1000_WUS_EX   0x00000004	/* Directed Exact Received */
+#define E1000_WUS_MC   0x00000008	/* Directed Multicast Received */
+#define E1000_WUS_BC   0x00000010	/* Broadcast Received */
+#define E1000_WUS_ARP  0x00000020	/* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040	/* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080	/* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000	/* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000	/* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000	/* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000	/* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000	/* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001	/* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002	/* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004	/* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100	/* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200	/* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400	/* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800	/* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000	/* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000	/* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000	/* Enable Neighbor Discovery
+						 * Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000	/* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000	/* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000	/* Status Reporting Enabled */
+#define E1000_MANC_SMB_REQ       0x01000000	/* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000	/* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000	/* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000	/* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000	/* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000	/* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28	/* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29	/* SMBus Clock Out Shift */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF	/* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN          4096
+
+/* EEPROM Commands */
+#define EEPROM_READ_OPCODE  0x6	/* EERPOM read opcode */
+#define EEPROM_WRITE_OPCODE 0x5	/* EERPOM write opcode */
+#define EEPROM_ERASE_OPCODE 0x7	/* EERPOM erase opcode */
+#define EEPROM_EWEN_OPCODE  0x13	/* EERPOM erase/write enable */
+#define EEPROM_EWDS_OPCODE  0x10	/* EERPOM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT              0x0003
+#define EEPROM_ID_LED_SETTINGS     0x0004
+#define EEPROM_INIT_CONTROL1_REG   0x000A
+#define EEPROM_INIT_CONTROL2_REG   0x000F
+#define EEPROM_FLASH_VERSION       0x0032
+#define EEPROM_CHECKSUM_REG        0x003F
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2 << 12) | \
+			      (ID_LED_OFF1_OFF2 << 8) | \
+			      (ID_LED_DEF1_DEF2 << 4) | \
+			      (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define EEPROM_COMPAT_SERVER 0x0400
+#define EEPROM_COMPAT_CLIENT 0x0200
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS   0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST   0x0200
+#define EEPROM_WORD0A_FD     0x0400
+#define EEPROM_WORD0A_66MHZ  0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE      0x1000
+#define EEPROM_WORD0F_ASM_DIR    0x2000
+#define EEPROM_WORD0F_ANE        0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1          8
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       16
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        64
+#define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_GB_HDX_COLLISION_DISTANCE 512
+#define E1000_COLD_SHIFT                12
+
+/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START     8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP      190
+#define TX_THRESHOLD_DISABLE   0
+#define TX_THRESHOLD_TIMER_MS  10000
+#define MIN_NUM_XMITS          1000
+#define IFS_MAX                80
+#define IFS_STEP               10
+#define IFS_MIN                40
+#define IFS_RATIO              4
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010	/* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030	/* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH        (0x8000)	/* 32KB */
+#define FC_DEFAULT_LO_THRESH        (0x4000)	/* 16KB */
+#define FC_DEFAULT_TX_TIMER         (0x100)	/* ~130 us */
+
+/* Flow Control High-Watermark: 43464 bytes */
+#define E1000_FC_HIGH_THRESH 0xA9C8
+/* Flow Control Low-Watermark: 43456 bytes */
+#define E1000_FC_LOW_THRESH 0xA9C0
+/* Flow Control Pause Time: 858 usec */
+#define E1000_FC_PAUSE_TIME 0x0680
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER    0xE6
+#define PCIX_STATUS_REGISTER_LO  0xE8
+#define PCIX_STATUS_REGISTER_HI  0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+
+/* The number of bits that we need to shift right to move the "pause"
+ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
+ * in the TXCW register
+ */
+#define PAUSE_SHIFT 5
+
+/* The number of bits that we need to shift left to move the "SWDPIO"
+ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
+ * in the CTRL register
+ */
+#define SWDPIO_SHIFT 17
+
+/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
+ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
+ * Extended CTRL register.
+ * in the CTRL register
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* The number of bits that we need to shift left to move the "ILOS"
+ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
+ * in the CTRL register
+ */
+#define ILOS_SHIFT  3
+
+#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
+
+/* The number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT             500
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct e1000_hw
+ *      status = the 8 bit status field of the RX descriptor with EOP set
+ *      error = the 8 bit error field of the RX descriptor with EOP set
+ *      length = the sum of all the length fields of the RX descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = TRUE;
+ *      e1000_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = FALSE;
+ *  }
+ *  ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+    ((adapter)->tbi_compatibility_on && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+	  (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+	   ((length) <= ((adapter)->max_frame_size + 1))) : \
+	  (((length) > (adapter)->min_frame_size) && \
+	   ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00	/* Control Register */
+#define PHY_STATUS       0x01	/* Status Regiser */
+#define PHY_ID1          0x02	/* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03	/* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04	/* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05	/* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06	/* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07	/* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08	/* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09	/* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A	/* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F	/* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10	/* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11	/* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12	/* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13	/* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14	/* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15	/* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F	/* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040	/* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080	/* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100	/* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200	/* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400	/* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800	/* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000	/* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000	/* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000	/* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000	/* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001	/* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002	/* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004	/* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008	/* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010	/* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020	/* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040	/* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100	/* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200	/* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400	/* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800	/* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000	/* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000	/* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000	/* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000	/* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001	/* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS    0x0020	/* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS    0x0040	/* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS  0x0080	/* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS  0x0100	/* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS     0x0200	/* 100T4 Capable */
+#define NWAY_AR_PAUSE          0x0400	/* Pause operation desired */
+#define NWAY_AR_ASM_DIR        0x0800	/* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT   0x2000	/* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE      0x8000	/* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000	/* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020	/* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040	/* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080	/* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100	/* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200	/* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400	/* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800	/* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000	/* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000	/* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000	/* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001	/* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002	/* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004	/* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008	/* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0100	/* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001	/* NP msg code or unformatted data */
+#define NPTX_TOGGLE         0x0800	/* Toggles between exchanges
+					 * of different NP
+					 */
+#define NPTX_ACKNOWLDGE2    0x1000	/* 1 = will comply with msg
+					 * 0 = cannot comply with msg
+					 */
+#define NPTX_MSG_PAGE       0x2000	/* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE      0x8000	/* 1 = addition NP will follow
+					 * 0 = sending last NP
+					 */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001	/* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE         0x0800	/* Toggles between exchanges
+					 * of different NP
+					 */
+#define LP_RNPR_ACKNOWLDGE2    0x1000	/* 1 = will comply with msg
+					 * 0 = cannot comply with msg
+					 */
+#define LP_RNPR_MSG_PAGE       0x2000	/* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE     0x4000	/* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE      0x8000	/* 1 = addition NP will follow
+					 * 0 = sending last NP
+					 */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080	/* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100	/* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200	/* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400	/* 1=Repeater/switch device port */
+					/* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800	/* 1=Configure PHY as Master */
+					/* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000	/* 1=Master/Slave manual config value */
+					/* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000	/* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000	/* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000	/* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000	/* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000	/* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF	/* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100	/* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400	/* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800	/* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000	/* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000	/* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000	/* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000	/* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT  13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000	/* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000	/* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000	/* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000	/* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK   0x0100	/* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0	/* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE  0x0010	/* register 11h bit 4 */
+				      /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001	/* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002	/* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004	/* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010	/* 1=CLK125 low,
+						 * 0=CLK125 toggling
+						 */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000	/* MDI Crossover Mode bits 6:5 */
+					       /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020	/* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040	/* 1000BASE-T: Auto crossover,
+						 *  100BASE-TX/10BASE-T:
+						 *  MDI Mode
+						 */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060	/* Auto crossover enabled
+						 * all speeds.
+						 */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+					/* 1=Enable Extended 10BASE-T distance
+					 * (Lower 10BASE-T RX Threshold)
+					 * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+					/* 1=5-Bit interface in 100BASE-TX
+					 * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200	/* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400	/* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800	/* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001	/* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002	/* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX               0x0040	/* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380	/* 0=<50M;1=50-80M;2=80-110M;
+						   * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK               0x0400	/* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800	/* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000	/* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000	/* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000	/* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000	/* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000	/* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000	/* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT         6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000	/* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000	/* 1=Lost lock detect enabled.
+						 * Will assert lost lock and bring
+						 * link down if idle not seen
+						 * within 1ms in 1000BASE-T
+						 */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060	/* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070	/* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000	/* NO  TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID  0x01410C50
+#define M88E1000_I_PHY_ID  0x01410C30
+#define M88E1011_I_PHY_ID  0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE        0xFFFFFFFF
+#define PHY_SOF             0x01
+#define PHY_OP_READ         0x02
+#define PHY_OP_WRITE        0x01
+#define PHY_TURNAROUND      0x02
+#define PHY_PREAMBLE_SIZE   32
+#define MII_CR_SPEED_1000   0x0040
+#define MII_CR_SPEED_100    0x2000
+#define MII_CR_SPEED_10     0x0000
+#define E1000_PHY_ADDRESS   0x01
+#define PHY_AUTO_NEG_TIME   45	/* 4.5 Seconds */
+#define PHY_FORCE_TIME      20	/* 2.0 Seconds */
+#define PHY_REVISION_MASK   0xFFFFFFF0
+#define DEVICE_SPEED_MASK   0x00000300	/* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK     0x01E0
+#define REG9_SPEED_MASK     0x0300
+#define ADVERTISE_10_HALF   0x0001
+#define ADVERTISE_10_FULL   0x0002
+#define ADVERTISE_100_HALF  0x0004
+#define ADVERTISE_100_FULL  0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F	/* Everything but 1000-Half */
+
+#endif				/* _E1000_HW_H_ */
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
new file mode 100644
index 0000000..738146e
--- /dev/null
+++ b/drivers/net/eepro100.c
@@ -0,0 +1,948 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+#undef DEBUG
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_EEPRO100)
+
+	/* Ethernet chip registers.
+	 */
+#define SCBStatus		0	/* Rx/Command Unit Status *Word* */
+#define SCBIntAckByte		1	/* Rx/Command Unit STAT/ACK byte */
+#define SCBCmd			2	/* Rx/Command Unit Command *Word* */
+#define SCBIntrCtlByte		3	/* Rx/Command Unit Intr.Control Byte */
+#define SCBPointer		4	/* General purpose pointer. */
+#define SCBPort			8	/* Misc. commands and operands. */
+#define SCBflash		12	/* Flash memory control. */
+#define SCBeeprom		14	/* EEPROM memory control. */
+#define SCBCtrlMDI		16	/* MDI interface control. */
+#define SCBEarlyRx		20	/* Early receive byte count. */
+#define SCBGenControl		28	/* 82559 General Control Register */
+#define SCBGenStatus		29	/* 82559 General Status register */
+
+	/* 82559 SCB status word defnitions
+	 */
+#define SCB_STATUS_CX		0x8000	/* CU finished command (transmit) */
+#define SCB_STATUS_FR		0x4000	/* frame received */
+#define SCB_STATUS_CNA		0x2000	/* CU left active state */
+#define SCB_STATUS_RNR		0x1000	/* receiver left ready state */
+#define SCB_STATUS_MDI		0x0800	/* MDI read/write cycle done */
+#define SCB_STATUS_SWI		0x0400	/* software generated interrupt */
+#define SCB_STATUS_FCP		0x0100	/* flow control pause interrupt */
+
+#define SCB_INTACK_MASK		0xFD00	/* all the above */
+
+#define SCB_INTACK_TX		(SCB_STATUS_CX | SCB_STATUS_CNA)
+#define SCB_INTACK_RX		(SCB_STATUS_FR | SCB_STATUS_RNR)
+
+	/* System control block commands
+	 */
+/* CU Commands */
+#define CU_NOP			0x0000
+#define CU_START		0x0010
+#define CU_RESUME		0x0020
+#define CU_STATSADDR		0x0040	/* Load Dump Statistics ctrs addr */
+#define CU_SHOWSTATS		0x0050	/* Dump statistics counters. */
+#define CU_ADDR_LOAD		0x0060	/* Base address to add to CU commands */
+#define CU_DUMPSTATS		0x0070	/* Dump then reset stats counters. */
+
+/* RUC Commands */
+#define RUC_NOP			0x0000
+#define RUC_START		0x0001
+#define RUC_RESUME		0x0002
+#define RUC_ABORT		0x0004
+#define RUC_ADDR_LOAD		0x0006	/* (seems not to clear on acceptance) */
+#define RUC_RESUMENR		0x0007
+
+#define CU_CMD_MASK		0x00f0
+#define RU_CMD_MASK		0x0007
+
+#define SCB_M			0x0100	/* 0 = enable interrupt, 1 = disable */
+#define SCB_SWI			0x0200	/* 1 - cause device to interrupt */
+
+#define CU_STATUS_MASK		0x00C0
+#define RU_STATUS_MASK		0x003C
+
+#define RU_STATUS_IDLE		(0<<2)
+#define RU_STATUS_SUS		(1<<2)
+#define RU_STATUS_NORES		(2<<2)
+#define RU_STATUS_READY		(4<<2)
+#define RU_STATUS_NO_RBDS_SUS	((1<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2))
+
+	/* 82559 Port interface commands.
+	 */
+#define I82559_RESET		0x00000000	/* Software reset */
+#define I82559_SELFTEST		0x00000001	/* 82559 Selftest command */
+#define I82559_SELECTIVE_RESET	0x00000002
+#define I82559_DUMP		0x00000003
+#define I82559_DUMP_WAKEUP	0x00000007
+
+	/* 82559 Eeprom interface.
+	 */
+#define EE_SHIFT_CLK		0x01	/* EEPROM shift clock. */
+#define EE_CS			0x02	/* EEPROM chip select. */
+#define EE_DATA_WRITE		0x04	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x05
+#define EE_DATA_READ		0x08	/* EEPROM chip data out. */
+#define EE_ENB			(0x4800 | EE_CS)
+#define EE_CMD_BITS		3
+#define EE_DATA_BITS		16
+
+	/* The EEPROM commands include the alway-set leading bit.
+	 */
+#define EE_EWENB_CMD		(4 << addr_len)
+#define EE_WRITE_CMD		(5 << addr_len)
+#define EE_READ_CMD		(6 << addr_len)
+#define EE_ERASE_CMD		(7 << addr_len)
+
+	/* Receive frame descriptors.
+	 */
+struct RxFD {
+	volatile u16 status;
+	volatile u16 control;
+	volatile u32 link;		/* struct RxFD * */
+	volatile u32 rx_buf_addr;	/* void * */
+	volatile u32 count;
+
+	volatile u8 data[PKTSIZE_ALIGN];
+};
+
+#define RFD_STATUS_C		0x8000	/* completion of received frame */
+#define RFD_STATUS_OK		0x2000	/* frame received with no errors */
+
+#define RFD_CONTROL_EL		0x8000	/* 1=last RFD in RFA */
+#define RFD_CONTROL_S		0x4000	/* 1=suspend RU after receiving frame */
+#define RFD_CONTROL_H		0x0010	/* 1=RFD is a header RFD */
+#define RFD_CONTROL_SF		0x0008	/* 0=simplified, 1=flexible mode */
+
+#define RFD_COUNT_MASK		0x3fff
+#define RFD_COUNT_F		0x4000
+#define RFD_COUNT_EOF		0x8000
+
+#define RFD_RX_CRC		0x0800	/* crc error */
+#define RFD_RX_ALIGNMENT	0x0400	/* alignment error */
+#define RFD_RX_RESOURCE		0x0200	/* out of space, no resources */
+#define RFD_RX_DMA_OVER		0x0100	/* DMA overrun */
+#define RFD_RX_SHORT		0x0080	/* short frame error */
+#define RFD_RX_LENGTH		0x0020
+#define RFD_RX_ERROR		0x0010	/* receive error */
+#define RFD_RX_NO_ADR_MATCH	0x0004	/* no address match */
+#define RFD_RX_IA_MATCH		0x0002	/* individual address does not match */
+#define RFD_RX_TCO		0x0001	/* TCO indication */
+
+	/* Transmit frame descriptors
+	 */
+struct TxFD {				/* Transmit frame descriptor set. */
+	volatile u16 status;
+	volatile u16 command;
+	volatile u32 link;		/* void * */
+	volatile u32 tx_desc_addr;	/* Always points to the tx_buf_addr element. */
+	volatile s32 count;
+
+	volatile u32 tx_buf_addr0;	/* void *, frame to be transmitted.  */
+	volatile s32 tx_buf_size0;	/* Length of Tx frame. */
+	volatile u32 tx_buf_addr1;	/* void *, frame to be transmitted.  */
+	volatile s32 tx_buf_size1;	/* Length of Tx frame. */
+};
+
+#define TxCB_CMD_TRANSMIT	0x0004	/* transmit command */
+#define TxCB_CMD_SF		0x0008	/* 0=simplified, 1=flexible mode */
+#define TxCB_CMD_NC		0x0010	/* 0=CRC insert by controller */
+#define TxCB_CMD_I		0x2000	/* generate interrupt on completion */
+#define TxCB_CMD_S		0x4000	/* suspend on completion */
+#define TxCB_CMD_EL		0x8000	/* last command block in CBL */
+
+#define TxCB_COUNT_MASK		0x3fff
+#define TxCB_COUNT_EOF		0x8000
+
+	/* The Speedo3 Rx and Tx frame/buffer descriptors.
+	 */
+struct descriptor {			/* A generic descriptor. */
+	volatile u16 status;
+	volatile u16 command;
+	volatile u32 link;		/* struct descriptor *	*/
+
+	unsigned char params[0];
+};
+
+#define CFG_CMD_EL		0x8000
+#define CFG_CMD_SUSPEND		0x4000
+#define CFG_CMD_INT		0x2000
+#define CFG_CMD_IAS		0x0001	/* individual address setup */
+#define CFG_CMD_CONFIGURE	0x0002	/* configure */
+
+#define CFG_STATUS_C		0x8000
+#define CFG_STATUS_OK		0x2000
+
+	/* Misc.
+	 */
+#define NUM_RX_DESC		PKTBUFSRX
+#define NUM_TX_DESC		1	/* Number of TX descriptors   */
+
+#define TOUT_LOOP		1000000
+
+#define ETH_ALEN		6
+
+static struct RxFD rx_ring[NUM_RX_DESC];	/* RX descriptor ring	      */
+static struct TxFD tx_ring[NUM_TX_DESC];	/* TX descriptor ring	      */
+static int rx_next;			/* RX descriptor ring pointer */
+static int tx_next;			/* TX descriptor ring pointer */
+static int tx_threshold;
+
+/*
+ * The parameters for a CmdConfigure operation.
+ * There are so many options that it would be difficult to document
+ * each bit. We mostly use the default or recommended settings.
+ */
+static const char i82557_config_cmd[] = {
+	22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1,	/* 1=Use MII  0=Use AUI */
+	0, 0x2E, 0, 0x60, 0,
+	0xf2, 0x48, 0, 0x40, 0xf2, 0x80,	/* 0x40=Force full-duplex */
+	0x3f, 0x05,
+};
+static const char i82558_config_cmd[] = {
+	22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1,	/* 1=Use MII  0=Use AUI */
+	0, 0x2E, 0, 0x60, 0x08, 0x88,
+	0x68, 0, 0x40, 0xf2, 0x84,		/* Disable FC */
+	0x31, 0x05,
+};
+
+static void init_rx_ring (struct eth_device *dev);
+static void purge_tx_ring (struct eth_device *dev);
+
+static void read_hw_addr (struct eth_device *dev, bd_t * bis);
+
+static int eepro100_init (struct eth_device *dev, bd_t * bis);
+static int eepro100_send (struct eth_device *dev, volatile void *packet,
+						  int length);
+static int eepro100_recv (struct eth_device *dev);
+static void eepro100_halt (struct eth_device *dev);
+
+#if defined(CONFIG_E500) || defined(CONFIG_DB64360) || defined(CONFIG_DB64460)
+#define bus_to_phys(a) (a)
+#define phys_to_bus(a) (a)
+#else
+#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+#endif
+
+static inline int INW (struct eth_device *dev, u_long addr)
+{
+	return le16_to_cpu (*(volatile u16 *) (addr + dev->iobase));
+}
+
+static inline void OUTW (struct eth_device *dev, int command, u_long addr)
+{
+	*(volatile u16 *) ((addr + dev->iobase)) = cpu_to_le16 (command);
+}
+
+static inline void OUTL (struct eth_device *dev, int command, u_long addr)
+{
+	*(volatile u32 *) ((addr + dev->iobase)) = cpu_to_le32 (command);
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static inline int INL (struct eth_device *dev, u_long addr)
+{
+	return le32_to_cpu (*(volatile u32 *) (addr + dev->iobase));
+}
+
+static int get_phyreg (struct eth_device *dev, unsigned char addr,
+		unsigned char reg, unsigned short *value)
+{
+	int cmd;
+	int timeout = 50;
+
+	/* read requested data */
+	cmd = (2 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
+	OUTL (dev, cmd, SCBCtrlMDI);
+
+	do {
+		udelay(1000);
+		cmd = INL (dev, SCBCtrlMDI);
+	} while (!(cmd & (1 << 28)) && (--timeout));
+
+	if (timeout == 0)
+		return -1;
+
+	*value = (unsigned short) (cmd & 0xffff);
+
+	return 0;
+}
+
+static int set_phyreg (struct eth_device *dev, unsigned char addr,
+		unsigned char reg, unsigned short value)
+{
+	int cmd;
+	int timeout = 50;
+
+	/* write requested data */
+	cmd = (1 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
+	OUTL (dev, cmd | value, SCBCtrlMDI);
+
+	while (!(INL (dev, SCBCtrlMDI) & (1 << 28)) && (--timeout))
+		udelay(1000);
+
+	if (timeout == 0)
+		return -1;
+
+	return 0;
+}
+
+/* Check if given phyaddr is valid, i.e. there is a PHY connected.
+ * Do this by checking model value field from ID2 register.
+ */
+static struct eth_device* verify_phyaddr (char *devname, unsigned char addr)
+{
+	struct eth_device *dev;
+	unsigned short value;
+	unsigned char model;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		return NULL;
+	}
+
+	/* read id2 register */
+	if (get_phyreg(dev, addr, PHY_PHYIDR2, &value) != 0) {
+		printf("%s: mii read timeout!\n", devname);
+		return NULL;
+	}
+
+	/* get model */
+	model = (unsigned char)((value >> 4) & 0x003f);
+
+	if (model == 0) {
+		printf("%s: no PHY at address %d\n", devname, addr);
+		return NULL;
+	}
+
+	return dev;
+}
+
+static int eepro100_miiphy_read (char *devname, unsigned char addr,
+		unsigned char reg, unsigned short *value)
+{
+	struct eth_device *dev;
+
+	dev = verify_phyaddr(devname, addr);
+	if (dev == NULL)
+		return -1;
+
+	if (get_phyreg(dev, addr, reg, value) != 0) {
+		printf("%s: mii read timeout!\n", devname);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int eepro100_miiphy_write (char *devname, unsigned char addr,
+		unsigned char reg, unsigned short value)
+{
+	struct eth_device *dev;
+
+	dev = verify_phyaddr(devname, addr);
+	if (dev == NULL)
+		return -1;
+
+	if (set_phyreg(dev, addr, reg, value) != 0) {
+		printf("%s: mii write timeout!\n", devname);
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif
+
+/* Wait for the chip get the command.
+*/
+static int wait_for_eepro100 (struct eth_device *dev)
+{
+	int i;
+
+	for (i = 0; INW (dev, SCBCmd) & (CU_CMD_MASK | RU_CMD_MASK); i++) {
+		if (i >= TOUT_LOOP) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER},
+	{}
+};
+
+int eepro100_initialize (bd_t * bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	u32 iobase, status;
+	int idx = 0;
+
+	while (1) {
+		/* Find PCI device
+		 */
+		if ((devno = pci_find_devices (supported, idx++)) < 0) {
+			break;
+		}
+
+		pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase);
+		iobase &= ~0xf;
+
+#ifdef DEBUG
+		printf ("eepro100: Intel i82559 PCI EtherExpressPro @0x%x\n",
+				iobase);
+#endif
+
+		pci_write_config_dword (devno,
+					PCI_COMMAND,
+					PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+		/* Check if I/O accesses and Bus Mastering are enabled.
+		 */
+		pci_read_config_dword (devno, PCI_COMMAND, &status);
+		if (!(status & PCI_COMMAND_MEMORY)) {
+			printf ("Error: Can not enable MEM access.\n");
+			continue;
+		}
+
+		if (!(status & PCI_COMMAND_MASTER)) {
+			printf ("Error: Can not enable Bus Mastering.\n");
+			continue;
+		}
+
+		dev = (struct eth_device *) malloc (sizeof *dev);
+
+		sprintf (dev->name, "i82559#%d", card_number);
+		dev->priv = (void *) devno; /* this have to come before bus_to_phys() */
+		dev->iobase = bus_to_phys (iobase);
+		dev->init = eepro100_init;
+		dev->halt = eepro100_halt;
+		dev->send = eepro100_send;
+		dev->recv = eepro100_recv;
+
+		eth_register (dev);
+
+#if defined (CONFIG_MII) || defined(CONFIG_CMD_MII)
+		/* register mii command access routines */
+		miiphy_register(dev->name,
+				eepro100_miiphy_read, eepro100_miiphy_write);
+#endif
+
+		card_number++;
+
+		/* Set the latency timer for value.
+		 */
+		pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
+
+		udelay (10 * 1000);
+
+		read_hw_addr (dev, bis);
+	}
+
+	return card_number;
+}
+
+
+static int eepro100_init (struct eth_device *dev, bd_t * bis)
+{
+	int i, status = 0;
+	int tx_cur;
+	struct descriptor *ias_cmd, *cfg_cmd;
+
+	/* Reset the ethernet controller
+	 */
+	OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
+	udelay (20);
+
+	OUTL (dev, I82559_RESET, SCBPort);
+	udelay (20);
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+	OUTL (dev, 0, SCBPointer);
+	OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+	OUTL (dev, 0, SCBPointer);
+	OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+	/* Initialize Rx and Tx rings.
+	 */
+	init_rx_ring (dev);
+	purge_tx_ring (dev);
+
+	/* Tell the adapter where the RX ring is located.
+	 */
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+
+	OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
+	OUTW (dev, SCB_M | RUC_START, SCBCmd);
+
+	/* Send the Configure frame */
+	tx_cur = tx_next;
+	tx_next = ((tx_next + 1) % NUM_TX_DESC);
+
+	cfg_cmd = (struct descriptor *) &tx_ring[tx_cur];
+	cfg_cmd->command = cpu_to_le16 ((CFG_CMD_SUSPEND | CFG_CMD_CONFIGURE));
+	cfg_cmd->status = 0;
+	cfg_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+
+	memcpy (cfg_cmd->params, i82558_config_cmd,
+			sizeof (i82558_config_cmd));
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error---CFG_CMD_CONFIGURE: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+
+	OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+	OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+	for (i = 0;
+	     !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+	     i++) {
+		if (i >= TOUT_LOOP) {
+			printf ("%s: Tx error buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+		printf ("TX error status = 0x%08X\n",
+			le16_to_cpu (tx_ring[tx_cur].status));
+		goto Done;
+	}
+
+	/* Send the Individual Address Setup frame
+	 */
+	tx_cur = tx_next;
+	tx_next = ((tx_next + 1) % NUM_TX_DESC);
+
+	ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
+	ias_cmd->command = cpu_to_le16 ((CFG_CMD_SUSPEND | CFG_CMD_IAS));
+	ias_cmd->status = 0;
+	ias_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+
+	memcpy (ias_cmd->params, dev->enetaddr, 6);
+
+	/* Tell the adapter where the TX ring is located.
+	 */
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+
+	OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+	OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+	for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+		 i++) {
+		if (i >= TOUT_LOOP) {
+			printf ("%s: Tx error buffer not ready\n",
+				dev->name);
+			goto Done;
+		}
+	}
+
+	if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+		printf ("TX error status = 0x%08X\n",
+			le16_to_cpu (tx_ring[tx_cur].status));
+		goto Done;
+	}
+
+	status = 1;
+
+  Done:
+	return status;
+}
+
+static int eepro100_send (struct eth_device *dev, volatile void *packet, int length)
+{
+	int i, status = -1;
+	int tx_cur;
+
+	if (length <= 0) {
+		printf ("%s: bad packet size: %d\n", dev->name, length);
+		goto Done;
+	}
+
+	tx_cur = tx_next;
+	tx_next = (tx_next + 1) % NUM_TX_DESC;
+
+	tx_ring[tx_cur].command = cpu_to_le16 ( TxCB_CMD_TRANSMIT |
+						TxCB_CMD_SF	|
+						TxCB_CMD_S	|
+						TxCB_CMD_EL );
+	tx_ring[tx_cur].status = 0;
+	tx_ring[tx_cur].count = cpu_to_le32 (tx_threshold);
+	tx_ring[tx_cur].link =
+		cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+	tx_ring[tx_cur].tx_desc_addr =
+		cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_cur].tx_buf_addr0));
+	tx_ring[tx_cur].tx_buf_addr0 =
+		cpu_to_le32 (phys_to_bus ((u_long) packet));
+	tx_ring[tx_cur].tx_buf_size0 = cpu_to_le32 (length);
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("%s: Tx error ethernet controller not ready.\n",
+				dev->name);
+		goto Done;
+	}
+
+	/* Send the packet.
+	 */
+	OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+	OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+	for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+		 i++) {
+		if (i >= TOUT_LOOP) {
+			printf ("%s: Tx error buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+		printf ("TX error status = 0x%08X\n",
+			le16_to_cpu (tx_ring[tx_cur].status));
+		goto Done;
+	}
+
+	status = length;
+
+  Done:
+	return status;
+}
+
+static int eepro100_recv (struct eth_device *dev)
+{
+	u16 status, stat;
+	int rx_prev, length = 0;
+
+	stat = INW (dev, SCBStatus);
+	OUTW (dev, stat & SCB_STATUS_RNR, SCBStatus);
+
+	for (;;) {
+		status = le16_to_cpu (rx_ring[rx_next].status);
+
+		if (!(status & RFD_STATUS_C)) {
+			break;
+		}
+
+		/* Valid frame status.
+		 */
+		if ((status & RFD_STATUS_OK)) {
+			/* A valid frame received.
+			 */
+			length = le32_to_cpu (rx_ring[rx_next].count) & 0x3fff;
+
+			/* Pass the packet up to the protocol
+			 * layers.
+			 */
+			NetReceive (rx_ring[rx_next].data, length);
+		} else {
+			/* There was an error.
+			 */
+			printf ("RX error status = 0x%08X\n", status);
+		}
+
+		rx_ring[rx_next].control = cpu_to_le16 (RFD_CONTROL_S);
+		rx_ring[rx_next].status = 0;
+		rx_ring[rx_next].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
+
+		rx_prev = (rx_next + NUM_RX_DESC - 1) % NUM_RX_DESC;
+		rx_ring[rx_prev].control = 0;
+
+		/* Update entry information.
+		 */
+		rx_next = (rx_next + 1) % NUM_RX_DESC;
+	}
+
+	if (stat & SCB_STATUS_RNR) {
+
+		printf ("%s: Receiver is not ready, restart it !\n", dev->name);
+
+		/* Reinitialize Rx ring.
+		 */
+		init_rx_ring (dev);
+
+		if (!wait_for_eepro100 (dev)) {
+			printf ("Error: Can not restart ethernet controller.\n");
+			goto Done;
+		}
+
+		OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
+		OUTW (dev, SCB_M | RUC_START, SCBCmd);
+	}
+
+  Done:
+	return length;
+}
+
+static void eepro100_halt (struct eth_device *dev)
+{
+	/* Reset the ethernet controller
+	 */
+	OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
+	udelay (20);
+
+	OUTL (dev, I82559_RESET, SCBPort);
+	udelay (20);
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+	OUTL (dev, 0, SCBPointer);
+	OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+	if (!wait_for_eepro100 (dev)) {
+		printf ("Error: Can not reset ethernet controller.\n");
+		goto Done;
+	}
+	OUTL (dev, 0, SCBPointer);
+	OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+  Done:
+	return;
+}
+
+	/* SROM Read.
+	 */
+static int read_eeprom (struct eth_device *dev, int location, int addr_len)
+{
+	unsigned short retval = 0;
+	int read_cmd = location | EE_READ_CMD;
+	int i;
+
+	OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
+	OUTW (dev, EE_ENB, SCBeeprom);
+
+	/* Shift the read command bits out. */
+	for (i = 12; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+
+		OUTW (dev, EE_ENB | dataval, SCBeeprom);
+		udelay (1);
+		OUTW (dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+		udelay (1);
+	}
+	OUTW (dev, EE_ENB, SCBeeprom);
+
+	for (i = 15; i >= 0; i--) {
+		OUTW (dev, EE_ENB | EE_SHIFT_CLK, SCBeeprom);
+		udelay (1);
+		retval = (retval << 1) |
+				((INW (dev, SCBeeprom) & EE_DATA_READ) ? 1 : 0);
+		OUTW (dev, EE_ENB, SCBeeprom);
+		udelay (1);
+	}
+
+	/* Terminate the EEPROM access. */
+	OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
+	return retval;
+}
+
+#ifdef CONFIG_EEPRO100_SROM_WRITE
+int eepro100_write_eeprom (struct eth_device* dev, int location, int addr_len, unsigned short data)
+{
+    unsigned short dataval;
+    int enable_cmd = 0x3f | EE_EWENB_CMD;
+    int write_cmd  = location | EE_WRITE_CMD;
+    int i;
+    unsigned long datalong, tmplong;
+
+    OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+    udelay(1);
+    OUTW(dev, EE_ENB, SCBeeprom);
+
+    /* Shift the enable command bits out. */
+    for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
+    {
+	dataval = (enable_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+	OUTW(dev, EE_ENB | dataval, SCBeeprom);
+	udelay(1);
+	OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+	udelay(1);
+    }
+
+    OUTW(dev, EE_ENB, SCBeeprom);
+    udelay(1);
+    OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+    udelay(1);
+    OUTW(dev, EE_ENB, SCBeeprom);
+
+
+    /* Shift the write command bits out. */
+    for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
+    {
+	dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+	OUTW(dev, EE_ENB | dataval, SCBeeprom);
+	udelay(1);
+	OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+	udelay(1);
+    }
+
+    /* Write the data */
+    datalong= (unsigned long) ((((data) & 0x00ff) << 8) | ( (data) >> 8));
+
+    for (i = 0; i< EE_DATA_BITS; i++)
+    {
+    /* Extract and move data bit to bit DI */
+    dataval = ((datalong & 0x8000)>>13) ? EE_DATA_WRITE : 0;
+
+    OUTW(dev, EE_ENB | dataval, SCBeeprom);
+    udelay(1);
+    OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+    udelay(1);
+    OUTW(dev, EE_ENB | dataval, SCBeeprom);
+    udelay(1);
+
+    datalong = datalong << 1;	/* Adjust significant data bit*/
+    }
+
+    /* Finish up command  (toggle CS) */
+    OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+    udelay(1);			/* delay for more than 250 ns */
+    OUTW(dev, EE_ENB, SCBeeprom);
+
+    /* Wait for programming ready (D0 = 1) */
+    tmplong = 10;
+    do
+    {
+	dataval = INW(dev, SCBeeprom);
+	if (dataval & EE_DATA_READ)
+	    break;
+	udelay(10000);
+    }
+    while (-- tmplong);
+
+    if (tmplong == 0)
+    {
+	printf ("Write i82559 eeprom timed out (100 ms waiting for data ready.\n");
+	return -1;
+    }
+
+    /* Terminate the EEPROM access. */
+    OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+
+    return 0;
+}
+#endif
+
+static void init_rx_ring (struct eth_device *dev)
+{
+	int i;
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		rx_ring[i].status = 0;
+		rx_ring[i].control =
+				(i == NUM_RX_DESC - 1) ? cpu_to_le16 (RFD_CONTROL_S) : 0;
+		rx_ring[i].link =
+				cpu_to_le32 (phys_to_bus
+							 ((u32) & rx_ring[(i + 1) % NUM_RX_DESC]));
+		rx_ring[i].rx_buf_addr = 0xffffffff;
+		rx_ring[i].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
+	}
+
+	rx_next = 0;
+}
+
+static void purge_tx_ring (struct eth_device *dev)
+{
+	int i;
+
+	tx_next = 0;
+	tx_threshold = 0x01208000;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tx_ring[i].status = 0;
+		tx_ring[i].command = 0;
+		tx_ring[i].link = 0;
+		tx_ring[i].tx_desc_addr = 0;
+		tx_ring[i].count = 0;
+
+		tx_ring[i].tx_buf_addr0 = 0;
+		tx_ring[i].tx_buf_size0 = 0;
+		tx_ring[i].tx_buf_addr1 = 0;
+		tx_ring[i].tx_buf_size1 = 0;
+	}
+}
+
+static void read_hw_addr (struct eth_device *dev, bd_t * bis)
+{
+	u16 eeprom[0x40];
+	u16 sum = 0;
+	int i, j;
+	int addr_len = read_eeprom (dev, 0, 6) == 0xffff ? 8 : 6;
+
+	for (j = 0, i = 0; i < 0x40; i++) {
+		u16 value = read_eeprom (dev, i, addr_len);
+
+		eeprom[i] = value;
+		sum += value;
+		if (i < 3) {
+			dev->enetaddr[j++] = value;
+			dev->enetaddr[j++] = value >> 8;
+		}
+	}
+
+	if (sum != 0xBABA) {
+		memset (dev->enetaddr, 0, ETH_ALEN);
+#ifdef DEBUG
+		printf ("%s: Invalid EEPROM checksum %#4.4x, "
+			"check settings before activating this device!\n",
+			dev->name, sum);
+#endif
+	}
+}
+
+#endif
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
new file mode 100644
index 0000000..98303ac
--- /dev/null
+++ b/drivers/net/enc28j60.c
@@ -0,0 +1,983 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#ifdef CONFIG_ENC28J60
+#include <net.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/spi.h>
+
+/*
+ * Control Registers in Bank 0
+ */
+
+#define CTL_REG_ERDPTL	 0x00
+#define CTL_REG_ERDPTH	 0x01
+#define CTL_REG_EWRPTL	 0x02
+#define CTL_REG_EWRPTH	 0x03
+#define CTL_REG_ETXSTL	 0x04
+#define CTL_REG_ETXSTH	 0x05
+#define CTL_REG_ETXNDL	 0x06
+#define CTL_REG_ETXNDH	 0x07
+#define CTL_REG_ERXSTL	 0x08
+#define CTL_REG_ERXSTH	 0x09
+#define CTL_REG_ERXNDL	 0x0A
+#define CTL_REG_ERXNDH	 0x0B
+#define CTL_REG_ERXRDPTL 0x0C
+#define CTL_REG_ERXRDPTH 0x0D
+#define CTL_REG_ERXWRPTL 0x0E
+#define CTL_REG_ERXWRPTH 0x0F
+#define CTL_REG_EDMASTL  0x10
+#define CTL_REG_EDMASTH  0x11
+#define CTL_REG_EDMANDL  0x12
+#define CTL_REG_EDMANDH  0x13
+#define CTL_REG_EDMADSTL 0x14
+#define CTL_REG_EDMADSTH 0x15
+#define CTL_REG_EDMACSL  0x16
+#define CTL_REG_EDMACSH  0x17
+/* these are common in all banks */
+#define CTL_REG_EIE	 0x1B
+#define CTL_REG_EIR	 0x1C
+#define CTL_REG_ESTAT	 0x1D
+#define CTL_REG_ECON2	 0x1E
+#define CTL_REG_ECON1	 0x1F
+
+/*
+ * Control Registers in Bank 1
+ */
+
+#define CTL_REG_EHT0	0x00
+#define CTL_REG_EHT1	0x01
+#define CTL_REG_EHT2	0x02
+#define CTL_REG_EHT3	0x03
+#define CTL_REG_EHT4	0x04
+#define CTL_REG_EHT5	0x05
+#define CTL_REG_EHT6	0x06
+#define CTL_REG_EHT7	0x07
+#define CTL_REG_EPMM0	0x08
+#define CTL_REG_EPMM1	0x09
+#define CTL_REG_EPMM2	0x0A
+#define CTL_REG_EPMM3	0x0B
+#define CTL_REG_EPMM4	0x0C
+#define CTL_REG_EPMM5	0x0D
+#define CTL_REG_EPMM6	0x0E
+#define CTL_REG_EPMM7	0x0F
+#define CTL_REG_EPMCSL	0x10
+#define CTL_REG_EPMCSH	0x11
+#define CTL_REG_EPMOL	0x14
+#define CTL_REG_EPMOH	0x15
+#define CTL_REG_EWOLIE	0x16
+#define CTL_REG_EWOLIR	0x17
+#define CTL_REG_ERXFCON 0x18
+#define CTL_REG_EPKTCNT 0x19
+
+/*
+ * Control Registers in Bank 2
+ */
+
+#define CTL_REG_MACON1	 0x00
+#define CTL_REG_MACON2	 0x01
+#define CTL_REG_MACON3	 0x02
+#define CTL_REG_MACON4	 0x03
+#define CTL_REG_MABBIPG  0x04
+#define CTL_REG_MAIPGL	 0x06
+#define CTL_REG_MAIPGH	 0x07
+#define CTL_REG_MACLCON1 0x08
+#define CTL_REG_MACLCON2 0x09
+#define CTL_REG_MAMXFLL  0x0A
+#define CTL_REG_MAMXFLH  0x0B
+#define CTL_REG_MAPHSUP  0x0D
+#define CTL_REG_MICON	 0x11
+#define CTL_REG_MICMD	 0x12
+#define CTL_REG_MIREGADR 0x14
+#define CTL_REG_MIWRL	 0x16
+#define CTL_REG_MIWRH	 0x17
+#define CTL_REG_MIRDL	 0x18
+#define CTL_REG_MIRDH	 0x19
+
+/*
+ * Control Registers in Bank 3
+ */
+
+#define CTL_REG_MAADR1	0x00
+#define CTL_REG_MAADR0	0x01
+#define CTL_REG_MAADR3	0x02
+#define CTL_REG_MAADR2	0x03
+#define CTL_REG_MAADR5	0x04
+#define CTL_REG_MAADR4	0x05
+#define CTL_REG_EBSTSD	0x06
+#define CTL_REG_EBSTCON 0x07
+#define CTL_REG_EBSTCSL 0x08
+#define CTL_REG_EBSTCSH 0x09
+#define CTL_REG_MISTAT	0x0A
+#define CTL_REG_EREVID	0x12
+#define CTL_REG_ECOCON	0x15
+#define CTL_REG_EFLOCON 0x17
+#define CTL_REG_EPAUSL	0x18
+#define CTL_REG_EPAUSH	0x19
+
+
+/*
+ * PHY Register
+ */
+
+#define PHY_REG_PHID1 0x02
+#define PHY_REG_PHID2 0x03
+/* taken from the Linux driver */
+#define PHY_REG_PHCON1 0x00
+#define PHY_REG_PHCON2 0x10
+#define PHY_REG_PHLCON 0x14
+
+/*
+ * Receive Filter Register (ERXFCON) bits
+ */
+
+#define ENC_RFR_UCEN  0x80
+#define ENC_RFR_ANDOR 0x40
+#define ENC_RFR_CRCEN 0x20
+#define ENC_RFR_PMEN  0x10
+#define ENC_RFR_MPEN  0x08
+#define ENC_RFR_HTEN  0x04
+#define ENC_RFR_MCEN  0x02
+#define ENC_RFR_BCEN  0x01
+
+/*
+ * ECON1 Register Bits
+ */
+
+#define ENC_ECON1_TXRST  0x80
+#define ENC_ECON1_RXRST  0x40
+#define ENC_ECON1_DMAST  0x20
+#define ENC_ECON1_CSUMEN 0x10
+#define ENC_ECON1_TXRTS  0x08
+#define ENC_ECON1_RXEN	 0x04
+#define ENC_ECON1_BSEL1  0x02
+#define ENC_ECON1_BSEL0  0x01
+
+/*
+ * ECON2 Register Bits
+ */
+#define ENC_ECON2_AUTOINC 0x80
+#define ENC_ECON2_PKTDEC  0x40
+#define ENC_ECON2_PWRSV   0x20
+#define ENC_ECON2_VRPS	  0x08
+
+/*
+ * EIR Register Bits
+ */
+#define ENC_EIR_PKTIF  0x40
+#define ENC_EIR_DMAIF  0x20
+#define ENC_EIR_LINKIF 0x10
+#define ENC_EIR_TXIF   0x08
+#define ENC_EIR_WOLIF  0x04
+#define ENC_EIR_TXERIF 0x02
+#define ENC_EIR_RXERIF 0x01
+
+/*
+ * ESTAT Register Bits
+ */
+
+#define ENC_ESTAT_INT	  0x80
+#define ENC_ESTAT_LATECOL 0x10
+#define ENC_ESTAT_RXBUSY  0x04
+#define ENC_ESTAT_TXABRT  0x02
+#define ENC_ESTAT_CLKRDY  0x01
+
+/*
+ * EIE Register Bits
+ */
+
+#define ENC_EIE_INTIE  0x80
+#define ENC_EIE_PKTIE  0x40
+#define ENC_EIE_DMAIE  0x20
+#define ENC_EIE_LINKIE 0x10
+#define ENC_EIE_TXIE   0x08
+#define ENC_EIE_WOLIE  0x04
+#define ENC_EIE_TXERIE 0x02
+#define ENC_EIE_RXERIE 0x01
+
+/*
+ * MACON1 Register Bits
+ */
+#define ENC_MACON1_LOOPBK  0x10
+#define ENC_MACON1_TXPAUS  0x08
+#define ENC_MACON1_RXPAUS  0x04
+#define ENC_MACON1_PASSALL 0x02
+#define ENC_MACON1_MARXEN  0x01
+
+
+/*
+ * MACON2 Register Bits
+ */
+#define ENC_MACON2_MARST   0x80
+#define ENC_MACON2_RNDRST  0x40
+#define ENC_MACON2_MARXRST 0x08
+#define ENC_MACON2_RFUNRST 0x04
+#define ENC_MACON2_MATXRST 0x02
+#define ENC_MACON2_TFUNRST 0x01
+
+/*
+ * MACON3 Register Bits
+ */
+#define ENC_MACON3_PADCFG2 0x80
+#define ENC_MACON3_PADCFG1 0x40
+#define ENC_MACON3_PADCFG0 0x20
+#define ENC_MACON3_TXCRCEN 0x10
+#define ENC_MACON3_PHDRLEN 0x08
+#define ENC_MACON3_HFRMEN  0x04
+#define ENC_MACON3_FRMLNEN 0x02
+#define ENC_MACON3_FULDPX  0x01
+
+/*
+ * MICMD Register Bits
+ */
+#define ENC_MICMD_MIISCAN 0x02
+#define ENC_MICMD_MIIRD   0x01
+
+/*
+ * MISTAT Register Bits
+ */
+#define ENC_MISTAT_NVALID 0x04
+#define ENC_MISTAT_SCAN   0x02
+#define ENC_MISTAT_BUSY   0x01
+
+/*
+ * PHID1 and PHID2 values
+ */
+#define ENC_PHID1_VALUE 0x0083
+#define ENC_PHID2_VALUE 0x1400
+#define ENC_PHID2_MASK	0xFC00
+
+
+#define ENC_SPI_SLAVE_CS 0x00010000	/* pin P1.16 */
+#define ENC_RESET	 0x00020000	/* pin P1.17 */
+
+#define FAILSAFE_VALUE 5000
+
+/*
+ * Controller memory layout:
+ *
+ * 0x0000 - 0x17ff  6k bytes receive buffer
+ * 0x1800 - 0x1fff  2k bytes transmit buffer
+ */
+/* Use the lower memory for receiver buffer. See errata pt. 5 */
+#define ENC_RX_BUF_START 0x0000
+#define ENC_TX_BUF_START 0x1800
+/* taken from the Linux driver */
+#define ENC_RX_BUF_END   0x17ff
+#define ENC_TX_BUF_END   0x1fff
+
+/* maximum frame length */
+#define ENC_MAX_FRM_LEN 1518
+
+#define enc_enable() PUT32(IO1CLR, ENC_SPI_SLAVE_CS)
+#define enc_disable() PUT32(IO1SET, ENC_SPI_SLAVE_CS)
+#define enc_cfg_spi() spi_set_cfg(0, 0, 0); spi_set_clock(8);
+
+
+static unsigned char encReadReg (unsigned char regNo);
+static void encWriteReg (unsigned char regNo, unsigned char data);
+static void encWriteRegRetry (unsigned char regNo, unsigned char data, int c);
+static void encReadBuff (unsigned short length, unsigned char *pBuff);
+static void encWriteBuff (unsigned short length, unsigned char *pBuff);
+static void encBitSet (unsigned char regNo, unsigned char data);
+static void encBitClr (unsigned char regNo, unsigned char data);
+static void encReset (void);
+static void encInit (unsigned char *pEthAddr);
+static unsigned short phyRead (unsigned char addr);
+static void phyWrite(unsigned char, unsigned short);
+static void encPoll (void);
+static void encRx (void);
+
+#define m_nic_read(reg) encReadReg(reg)
+#define m_nic_write(reg, data) encWriteReg(reg, data)
+#define m_nic_write_retry(reg, data, count) encWriteRegRetry(reg, data, count)
+#define m_nic_read_data(len, buf) encReadBuff((len), (buf))
+#define m_nic_write_data(len, buf) encWriteBuff((len), (buf))
+
+/* bit field set */
+#define m_nic_bfs(reg, data) encBitSet(reg, data)
+
+/* bit field clear */
+#define m_nic_bfc(reg, data) encBitClr(reg, data)
+
+static unsigned char bank = 0;	/* current bank in enc28j60 */
+static unsigned char next_pointer_lsb;
+static unsigned char next_pointer_msb;
+
+static unsigned char buffer[ENC_MAX_FRM_LEN];
+static int rxResetCounter = 0;
+
+#define RX_RESET_COUNTER 1000;
+
+/*-----------------------------------------------------------------------------
+ * Always returns 0
+ */
+int eth_init (bd_t * bis)
+{
+	unsigned char estatVal;
+
+	/* configure GPIO */
+	(*((volatile unsigned long *) IO1DIR)) |= ENC_SPI_SLAVE_CS;
+	(*((volatile unsigned long *) IO1DIR)) |= ENC_RESET;
+
+	/* CS and RESET active low */
+	PUT32 (IO1SET, ENC_SPI_SLAVE_CS);
+	PUT32 (IO1SET, ENC_RESET);
+
+	spi_init ();
+
+	/* taken from the Linux driver - dangerous stuff here! */
+	/* Wait for CLKRDY to become set (i.e., check that we can communicate with
+	   the ENC) */
+	do
+	{
+		estatVal = m_nic_read(CTL_REG_ESTAT);
+	} while ((estatVal & 0x08) || (~estatVal & ENC_ESTAT_CLKRDY));
+
+	/* initialize controller */
+	encReset ();
+	encInit (bis->bi_enetaddr);
+
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+
+	return 0;
+}
+
+int eth_send (volatile void *packet, int length)
+{
+	/* check frame length, etc. */
+	/* TODO: */
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	/* set EWRPT */
+	m_nic_write (CTL_REG_EWRPTL, (ENC_TX_BUF_START & 0xff));
+	m_nic_write (CTL_REG_EWRPTH, (ENC_TX_BUF_START >> 8));
+
+	/* set ETXND */
+	m_nic_write (CTL_REG_ETXNDL, (length + ENC_TX_BUF_START) & 0xFF);
+	m_nic_write (CTL_REG_ETXNDH, (length + ENC_TX_BUF_START) >> 8);
+
+	/* set ETXST */
+	m_nic_write (CTL_REG_ETXSTL, ENC_TX_BUF_START & 0xFF);
+	m_nic_write (CTL_REG_ETXSTH, ENC_TX_BUF_START >> 8);
+
+	/* write packet */
+	m_nic_write_data (length, (unsigned char *) packet);
+
+	/* taken from the Linux driver */
+	/* Verify that the internal transmit logic has not been altered by excessive
+	   collisions.  See Errata B4 12 and 14.
+	 */
+	if (m_nic_read(CTL_REG_EIR) & ENC_EIR_TXERIF) {
+		m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_TXRST);
+		m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_TXRST);
+	}
+	m_nic_bfc(CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
+
+	/* set ECON1.TXRTS */
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_TXRTS);
+
+	return 0;
+}
+
+
+/*****************************************************************************
+ * This function resets the receiver only. This function may be called from
+ * interrupt-context.
+ */
+static void encReceiverReset (void)
+{
+	unsigned char econ1;
+
+	econ1 = m_nic_read (CTL_REG_ECON1);
+	if ((econ1 & ENC_ECON1_RXRST) == 0) {
+		m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXRST);
+		rxResetCounter = RX_RESET_COUNTER;
+	}
+}
+
+/*****************************************************************************
+ * receiver reset timer
+ */
+static void encReceiverResetCallback (void)
+{
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_RXRST);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+}
+
+/*-----------------------------------------------------------------------------
+ * Check for received packets. Call NetReceive for each packet. The return
+ * value is ignored by the caller.
+ */
+int eth_rx (void)
+{
+	if (rxResetCounter > 0 && --rxResetCounter == 0) {
+		encReceiverResetCallback ();
+	}
+
+	encPoll ();
+
+	return 0;
+}
+
+void eth_halt (void)
+{
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* disable receive */
+}
+
+/*****************************************************************************/
+
+static void encPoll (void)
+{
+	unsigned char eir_reg;
+	volatile unsigned char estat_reg;
+	unsigned char pkt_cnt;
+
+#ifdef CONFIG_USE_IRQ
+	/* clear global interrupt enable bit in enc28j60 */
+	m_nic_bfc (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+	estat_reg = m_nic_read (CTL_REG_ESTAT);
+
+	eir_reg = m_nic_read (CTL_REG_EIR);
+
+	if (eir_reg & ENC_EIR_TXIF) {
+		/* clear TXIF bit in EIR */
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_TXIF);
+	}
+
+	/* We have to use pktcnt and not pktif bit, see errata pt. 6 */
+
+	/* move to bank 1 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+	/* read pktcnt */
+	pkt_cnt = m_nic_read (CTL_REG_EPKTCNT);
+
+	if (pkt_cnt > 0) {
+		if ((eir_reg & ENC_EIR_PKTIF) == 0) {
+			/*printf("encPoll: pkt cnt > 0, but pktif not set\n"); */
+		}
+		encRx ();
+		/* clear PKTIF bit in EIR, this should not need to be done but it
+		   seems like we get problems if we do not */
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_PKTIF);
+	}
+
+	if (eir_reg & ENC_EIR_RXERIF) {
+		printf ("encPoll: rx error\n");
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_RXERIF);
+	}
+	if (eir_reg & ENC_EIR_TXERIF) {
+		printf ("encPoll: tx error\n");
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_TXERIF);
+	}
+
+#ifdef CONFIG_USE_IRQ
+	/* set global interrupt enable bit in enc28j60 */
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+static void encRx (void)
+{
+	unsigned short pkt_len;
+	unsigned short copy_len;
+	unsigned short status;
+	unsigned char eir_reg;
+	unsigned char pkt_cnt = 0;
+	unsigned short rxbuf_rdpt;
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	m_nic_write (CTL_REG_ERDPTL, next_pointer_lsb);
+	m_nic_write (CTL_REG_ERDPTH, next_pointer_msb);
+
+	do {
+		m_nic_read_data (6, buffer);
+		next_pointer_lsb = buffer[0];
+		next_pointer_msb = buffer[1];
+		pkt_len = buffer[2];
+		pkt_len |= (unsigned short) buffer[3] << 8;
+		status = buffer[4];
+		status |= (unsigned short) buffer[5] << 8;
+
+		if (pkt_len <= ENC_MAX_FRM_LEN)
+			copy_len = pkt_len;
+		else
+			copy_len = 0;
+
+		if ((status & (1L << 7)) == 0) /* check Received Ok bit */
+			copy_len = 0;
+
+		/* taken from the Linux driver */
+		/* check if next pointer is resonable */
+		if ((((unsigned int)next_pointer_msb << 8) |
+			(unsigned int)next_pointer_lsb) >= ENC_TX_BUF_START)
+			copy_len = 0;
+
+		if (copy_len > 0) {
+			m_nic_read_data (copy_len, buffer);
+		}
+
+		/* advance read pointer to next pointer */
+		m_nic_write (CTL_REG_ERDPTL, next_pointer_lsb);
+		m_nic_write (CTL_REG_ERDPTH, next_pointer_msb);
+
+		/* decrease packet counter */
+		m_nic_bfs (CTL_REG_ECON2, ENC_ECON2_PKTDEC);
+
+		/* taken from the Linux driver */
+		/* Only odd values should be written to ERXRDPTL,
+		 * see errata B4 pt.13
+		 */
+		rxbuf_rdpt = (next_pointer_msb << 8 | next_pointer_lsb) - 1;
+		if ((rxbuf_rdpt < (m_nic_read(CTL_REG_ERXSTH) << 8 |
+				m_nic_read(CTL_REG_ERXSTL))) || (rxbuf_rdpt >
+				(m_nic_read(CTL_REG_ERXNDH) << 8 |
+				m_nic_read(CTL_REG_ERXNDL)))) {
+			m_nic_write(CTL_REG_ERXRDPTL, m_nic_read(CTL_REG_ERXNDL));
+			m_nic_write(CTL_REG_ERXRDPTH, m_nic_read(CTL_REG_ERXNDH));
+		} else {
+			m_nic_write(CTL_REG_ERXRDPTL, rxbuf_rdpt & 0xFF);
+			m_nic_write(CTL_REG_ERXRDPTH, rxbuf_rdpt >> 8);
+		}
+
+		/* move to bank 1 */
+		m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+		m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+		/* read pktcnt */
+		pkt_cnt = m_nic_read (CTL_REG_EPKTCNT);
+
+		/* switch to bank 0 */
+		m_nic_bfc (CTL_REG_ECON1,
+			   (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+		if (copy_len == 0) {
+			eir_reg = m_nic_read (CTL_REG_EIR);
+			encReceiverReset ();
+			printf ("eth_rx: copy_len=0\n");
+			continue;
+		}
+
+		NetReceive ((unsigned char *) buffer, pkt_len);
+
+		eir_reg = m_nic_read (CTL_REG_EIR);
+	} while (pkt_cnt);	/* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
+}
+
+static void encWriteReg (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x40 | regNo);	/* write in regNo */
+	spi_write (data);
+
+	enc_disable ();
+	enc_enable ();
+
+	spi_write (0x1f);	/* write reg 0x1f */
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encWriteRegRetry (unsigned char regNo, unsigned char data, int c)
+{
+	unsigned char readback;
+	int i;
+
+	spi_lock ();
+
+	for (i = 0; i < c; i++) {
+		enc_cfg_spi ();
+		enc_enable ();
+
+		spi_write (0x40 | regNo);	/* write in regNo */
+		spi_write (data);
+
+		enc_disable ();
+		enc_enable ();
+
+		spi_write (0x1f);	/* write reg 0x1f */
+
+		enc_disable ();
+
+		spi_unlock ();	/* we must unlock spi first */
+
+		readback = encReadReg (regNo);
+
+		spi_lock ();
+
+		if (readback == data)
+			break;
+	}
+	spi_unlock ();
+
+	if (i == c) {
+		printf ("enc28j60: write reg %d failed\n", regNo);
+	}
+}
+
+static unsigned char encReadReg (unsigned char regNo)
+{
+	unsigned char rxByte;
+
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x1f);	/* read reg 0x1f */
+
+	bank = spi_read () & 0x3;
+
+	enc_disable ();
+	enc_enable ();
+
+	spi_write (regNo);
+	rxByte = spi_read ();
+
+	/* check if MAC or MII register */
+	if (((bank == 2) && (regNo <= 0x1a)) ||
+	    ((bank == 3) && (regNo <= 0x05 || regNo == 0x0a))) {
+		/* ignore first byte and read another byte */
+		rxByte = spi_read ();
+	}
+
+	enc_disable ();
+	spi_unlock ();
+
+	return rxByte;
+}
+
+static void encReadBuff (unsigned short length, unsigned char *pBuff)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x20 | 0x1a);	/* read buffer memory */
+
+	while (length--) {
+		if (pBuff != NULL)
+			*pBuff++ = spi_read ();
+		else
+			spi_write (0);
+	}
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encWriteBuff (unsigned short length, unsigned char *pBuff)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x60 | 0x1a);	/* write buffer memory */
+
+	spi_write (0x00);	/* control byte */
+
+	while (length--)
+		spi_write (*pBuff++);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encBitSet (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x80 | regNo);	/* bit field set */
+	spi_write (data);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encBitClr (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0xA0 | regNo);	/* bit field clear */
+	spi_write (data);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encReset (void)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0xff);	/* soft reset */
+
+	enc_disable ();
+	spi_unlock ();
+
+	/* sleep 1 ms. See errata pt. 2 */
+	udelay (1000);
+}
+
+static void encInit (unsigned char *pEthAddr)
+{
+	unsigned short phid1 = 0;
+	unsigned short phid2 = 0;
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	/*
+	 * Setup the buffer space. The reset values are valid for the
+	 * other pointers.
+	 */
+	/* We shall not write to ERXST, see errata pt. 5. Instead we
+	   have to make sure that ENC_RX_BUS_START is 0. */
+	m_nic_write_retry (CTL_REG_ERXSTL, (ENC_RX_BUF_START & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERXSTH, (ENC_RX_BUF_START >> 8), 1);
+
+	/* taken from the Linux driver */
+	m_nic_write_retry (CTL_REG_ERXNDL, (ENC_RX_BUF_END & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERXNDH, (ENC_RX_BUF_END >> 8), 1);
+
+	m_nic_write_retry (CTL_REG_ERDPTL, (ENC_RX_BUF_START & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERDPTH, (ENC_RX_BUF_START >> 8), 1);
+
+	next_pointer_lsb = (ENC_RX_BUF_START & 0xFF);
+	next_pointer_msb = (ENC_RX_BUF_START >> 8);
+
+	/* verify identification */
+	phid1 = phyRead (PHY_REG_PHID1);
+	phid2 = phyRead (PHY_REG_PHID2);
+
+	if (phid1 != ENC_PHID1_VALUE
+	    || (phid2 & ENC_PHID2_MASK) != ENC_PHID2_VALUE) {
+		printf ("ERROR: failed to identify controller\n");
+		printf ("phid1 = %x, phid2 = %x\n",
+			phid1, (phid2 & ENC_PHID2_MASK));
+		printf ("should be phid1 = %x, phid2 = %x\n",
+			ENC_PHID1_VALUE, ENC_PHID2_VALUE);
+	}
+
+	/*
+	 * --- MAC Initialization ---
+	 */
+
+	/* Pull MAC out of Reset */
+
+	/* switch to bank 2 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* enable MAC to receive frames */
+	/* added some bits from the Linux driver */
+	m_nic_write_retry (CTL_REG_MACON1
+		,(ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS)
+		,10);
+
+	/* configure pad, tx-crc and duplex */
+	/* added a bit from the Linux driver */
+	m_nic_write_retry (CTL_REG_MACON3
+		,(ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN | ENC_MACON3_FRMLNEN)
+		,10);
+
+	/* added 4 new lines from the Linux driver */
+	/* Allow infinite deferals if the medium is continously busy */
+	m_nic_write_retry(CTL_REG_MACON4, (1<<6) /*ENC_MACON4_DEFER*/, 10);
+
+	/* Late collisions occur beyond 63 bytes */
+	m_nic_write_retry(CTL_REG_MACLCON2, 63, 10);
+
+	/* Set (low byte) Non-Back-to_Back Inter-Packet Gap. Recommended 0x12 */
+	m_nic_write_retry(CTL_REG_MAIPGL, 0x12, 10);
+
+	/*
+	* Set (high byte) Non-Back-to_Back Inter-Packet Gap. Recommended
+	* 0x0c for half-duplex. Nothing for full-duplex
+	*/
+	m_nic_write_retry(CTL_REG_MAIPGH, 0x0C, 10);
+
+	/* set maximum frame length */
+	m_nic_write_retry (CTL_REG_MAMXFLL, (ENC_MAX_FRM_LEN & 0xff), 10);
+	m_nic_write_retry (CTL_REG_MAMXFLH, (ENC_MAX_FRM_LEN >> 8), 10);
+
+	/*
+	 * Set MAC back-to-back inter-packet gap. Recommended 0x12 for half duplex
+	 * and 0x15 for full duplex.
+	 */
+	m_nic_write_retry (CTL_REG_MABBIPG, 0x12, 10);
+
+	/* set MAC address */
+
+	/* switch to bank 3 */
+	m_nic_bfs (CTL_REG_ECON1, (ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1));
+
+	m_nic_write_retry (CTL_REG_MAADR0, pEthAddr[5], 1);
+	m_nic_write_retry (CTL_REG_MAADR1, pEthAddr[4], 1);
+	m_nic_write_retry (CTL_REG_MAADR2, pEthAddr[3], 1);
+	m_nic_write_retry (CTL_REG_MAADR3, pEthAddr[2], 1);
+	m_nic_write_retry (CTL_REG_MAADR4, pEthAddr[1], 1);
+	m_nic_write_retry (CTL_REG_MAADR5, pEthAddr[0], 1);
+
+	/*
+	* PHY Initialization taken from the Linux driver
+	 */
+
+	/* Prevent automatic loopback of data beeing transmitted by setting
+	   ENC_PHCON2_HDLDIS */
+	phyWrite(PHY_REG_PHCON2, (1<<8));
+
+	/* LEDs configuration
+	 * LEDA: LACFG = 0100 -> display link status
+	 * LEDB: LBCFG = 0111 -> display TX & RX activity
+	 * STRCH = 1 -> LED pulses
+	 */
+	phyWrite(PHY_REG_PHLCON, 0x0472);
+
+	/* Reset PDPXMD-bit => half duplex */
+	phyWrite(PHY_REG_PHCON1, 0);
+
+	/*
+	 * Receive settings
+	 */
+
+#ifdef CONFIG_USE_IRQ
+	/* enable interrupts */
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_PKTIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_TXIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_RXERIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_TXERIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+/*****************************************************************************
+ *
+ * Description:
+ *    Read PHY registers.
+ *
+ *    NOTE! This function will change to Bank 2.
+ *
+ * Params:
+ *    [in] addr address of the register to read
+ *
+ * Returns:
+ *    The value in the register
+ */
+static unsigned short phyRead (unsigned char addr)
+{
+	unsigned short ret = 0;
+
+	/* move to bank 2 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* write address to MIREGADR */
+	m_nic_write (CTL_REG_MIREGADR, addr);
+
+	/* set MICMD.MIIRD */
+	m_nic_write (CTL_REG_MICMD, ENC_MICMD_MIIRD);
+
+	/* taken from the Linux driver */
+	/* move to bank 3 */
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* poll MISTAT.BUSY bit until operation is complete */
+	while ((m_nic_read (CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		static int cnt = 0;
+
+		if (cnt++ >= 1000) {
+			/* GJ - this seems extremely dangerous! */
+			/* printf("#"); */
+			cnt = 0;
+		}
+	}
+
+	/* taken from the Linux driver */
+	/* move to bank 2 */
+	m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* clear MICMD.MIIRD */
+	m_nic_write (CTL_REG_MICMD, 0);
+
+	ret = (m_nic_read (CTL_REG_MIRDH) << 8);
+	ret |= (m_nic_read (CTL_REG_MIRDL) & 0xFF);
+
+	return ret;
+}
+
+/*****************************************************************************
+ *
+ * Taken from the Linux driver.
+ * Description:
+ * Write PHY registers.
+ *
+ * NOTE! This function will change to Bank 3.
+ *
+ * Params:
+ * [in] addr address of the register to write to
+ * [in] data to be written
+ *
+ * Returns:
+ *    None
+ */
+static void phyWrite(unsigned char addr, unsigned short data)
+{
+	/* move to bank 2 */
+	m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* write address to MIREGADR */
+	m_nic_write(CTL_REG_MIREGADR, addr);
+
+	m_nic_write(CTL_REG_MIWRL, data & 0xff);
+	m_nic_write(CTL_REG_MIWRH, data >> 8);
+
+	/* move to bank 3 */
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* poll MISTAT.BUSY bit until operation is complete */
+	while((m_nic_read(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		static int cnt = 0;
+
+		if(cnt++ >= 1000) {
+			cnt = 0;
+		}
+	}
+}
+
+#endif /* CONFIG_ENC28J60 */
diff --git a/drivers/net/inca-ip_sw.c b/drivers/net/inca-ip_sw.c
new file mode 100644
index 0000000..e4aaed6
--- /dev/null
+++ b/drivers/net/inca-ip_sw.c
@@ -0,0 +1,817 @@
+/*
+ * INCA-IP internal switch ethernet driver.
+ *
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_INCA_IP_SWITCH)
+
+#include <malloc.h>
+#include <net.h>
+#include <asm/inca-ip.h>
+#include <asm/addrspace.h>
+
+
+#define NUM_RX_DESC	PKTBUFSRX
+#define NUM_TX_DESC	3
+#define TOUT_LOOP	1000000
+
+
+#define DELAY	udelay(10000)
+  /* Sometimes the store word instruction hangs while writing to one
+   * of the Switch registers. Moving the instruction into a separate
+   * function somehow makes the problem go away.
+   */
+static void SWORD(volatile u32 * reg, u32 value)
+{
+	*reg = value;
+}
+
+#define DMA_WRITE_REG(reg, value) *((volatile u32 *)reg) = (u32)value;
+#define DMA_READ_REG(reg, value)    value = (u32)*((volatile u32*)reg)
+#define SW_WRITE_REG(reg, value)   \
+	SWORD(reg, value);\
+	DELAY;\
+	SWORD(reg, value);
+
+#define SW_READ_REG(reg, value)	   \
+	value = (u32)*((volatile u32*)reg);\
+	DELAY;\
+	value = (u32)*((volatile u32*)reg);
+
+#define INCA_DMA_TX_POLLING_TIME	0x07
+#define INCA_DMA_RX_POLLING_TIME	0x07
+
+#define INCA_DMA_TX_HOLD		0x80000000
+#define INCA_DMA_TX_EOP			0x40000000
+#define INCA_DMA_TX_SOP			0x20000000
+#define INCA_DMA_TX_ICPT		0x10000000
+#define INCA_DMA_TX_IEOP		0x08000000
+
+#define INCA_DMA_RX_C			0x80000000
+#define INCA_DMA_RX_SOP			0x40000000
+#define INCA_DMA_RX_EOP			0x20000000
+
+#define INCA_SWITCH_PHY_SPEED_10H	0x1
+#define INCA_SWITCH_PHY_SPEED_10F	0x5
+#define INCA_SWITCH_PHY_SPEED_100H	0x2
+#define INCA_SWITCH_PHY_SPEED_100F	0x6
+
+/************************ Auto MDIX settings ************************/
+#define INCA_IP_AUTO_MDIX_LAN_PORTS_DIR		INCA_IP_Ports_P1_DIR
+#define INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL	INCA_IP_Ports_P1_ALTSEL
+#define INCA_IP_AUTO_MDIX_LAN_PORTS_OUT		INCA_IP_Ports_P1_OUT
+#define INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX	16
+
+#define WAIT_SIGNAL_RETRIES			100
+#define WAIT_LINK_RETRIES			100
+#define LINK_RETRY_DELAY			2000  /* ms */
+/********************************************************************/
+
+typedef struct
+{
+	union {
+		struct {
+			volatile u32 HOLD		:1;
+			volatile u32 ICpt		:1;
+			volatile u32 IEop		:1;
+			volatile u32 offset		:3;
+			volatile u32 reserved0		:4;
+			volatile u32 NFB		:22;
+		}field;
+
+		volatile u32 word;
+	}params;
+
+	volatile u32 nextRxDescPtr;
+
+	volatile u32 RxDataPtr;
+
+	union {
+		struct {
+			volatile u32 C			:1;
+			volatile u32 Sop		:1;
+			volatile u32 Eop		:1;
+			volatile u32 reserved3		:12;
+			volatile u32 NBT		:17;
+		}field;
+
+		volatile u32 word;
+	}status;
+
+} inca_rx_descriptor_t;
+
+
+typedef struct
+{
+	union {
+		struct {
+			volatile u32 HOLD		:1;
+			volatile u32 Eop		:1;
+			volatile u32 Sop		:1;
+			volatile u32 ICpt		:1;
+			volatile u32 IEop		:1;
+			volatile u32 reserved0		:5;
+			volatile u32 NBA		:22;
+		}field;
+
+		volatile u32 word;
+	}params;
+
+	volatile u32 nextTxDescPtr;
+
+	volatile u32 TxDataPtr;
+
+	volatile u32 C			:1;
+	volatile u32 reserved3		:31;
+
+} inca_tx_descriptor_t;
+
+
+static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16)));
+static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16)));
+
+static int tx_new, rx_new, tx_hold, rx_hold;
+static int tx_old_hold = -1;
+static int initialized	= 0;
+
+
+static int inca_switch_init(struct eth_device *dev, bd_t * bis);
+static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length);
+static int inca_switch_recv(struct eth_device *dev);
+static void inca_switch_halt(struct eth_device *dev);
+static void inca_init_switch_chip(void);
+static void inca_dma_init(void);
+static int inca_amdix(void);
+
+
+int inca_switch_initialize(bd_t * bis)
+{
+	struct eth_device *dev;
+
+#if 0
+	printf("Entered inca_switch_initialize()\n");
+#endif
+
+	if (!(dev = (struct eth_device *) malloc (sizeof *dev))) {
+		printf("Failed to allocate memory\n");
+		return 0;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	inca_dma_init();
+
+	inca_init_switch_chip();
+
+#if defined(CONFIG_INCA_IP_SWITCH_AMDIX)
+	inca_amdix();
+#endif
+
+	sprintf(dev->name, "INCA-IP Switch");
+	dev->init = inca_switch_init;
+	dev->halt = inca_switch_halt;
+	dev->send = inca_switch_send;
+	dev->recv = inca_switch_recv;
+
+	eth_register(dev);
+
+#if 0
+	printf("Leaving inca_switch_initialize()\n");
+#endif
+
+	return 1;
+}
+
+
+static int inca_switch_init(struct eth_device *dev, bd_t * bis)
+{
+	int i;
+	u32 v, regValue;
+	u16 wTmp;
+
+#if 0
+	printf("Entering inca_switch_init()\n");
+#endif
+
+	/* Set MAC address.
+	 */
+	wTmp = (u16)dev->enetaddr[0];
+	regValue = (wTmp << 8) | dev->enetaddr[1];
+
+	SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue);
+
+	wTmp = (u16)dev->enetaddr[2];
+	regValue = (wTmp << 8) | dev->enetaddr[3];
+	regValue = regValue << 16;
+	wTmp = (u16)dev->enetaddr[4];
+	regValue |= (wTmp<<8) | dev->enetaddr[5];
+
+	SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue);
+
+	/* Initialize the descriptor rings.
+	 */
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]);
+		memset(rx_desc, 0, sizeof(rx_ring[i]));
+
+		/* Set maximum size of receive buffer.
+		 */
+		rx_desc->params.field.NFB = PKTSIZE_ALIGN;
+
+		/* Set the offset of the receive buffer. Zero means
+		 * that the offset mechanism is not used.
+		 */
+		rx_desc->params.field.offset = 0;
+
+		/* Check if it is the last descriptor.
+		 */
+		if (i == (NUM_RX_DESC - 1)) {
+			/* Let the last descriptor point to the first
+			 * one.
+			 */
+			rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring);
+		} else {
+			/* Set the address of the next descriptor.
+			 */
+			rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]);
+		}
+
+		rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]);
+	}
+
+#if 0
+	printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]);
+	printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]);
+#endif
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]);
+
+		memset(tx_desc, 0, sizeof(tx_ring[i]));
+
+		tx_desc->params.word	   = 0;
+		tx_desc->params.field.HOLD = 1;
+		tx_desc->C		   = 1;
+
+			/* Check if it is the last descriptor.
+			 */
+		if (i == (NUM_TX_DESC - 1)) {
+				/* Let the last descriptor point to the
+				 * first one.
+				 */
+			tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring);
+		} else {
+				/* Set the address of the next descriptor.
+				 */
+			tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]);
+		}
+	}
+
+	/* Initialize RxDMA.
+	 */
+	DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v);
+#if 0
+	printf("RX status = 0x%08X\n", v);
+#endif
+
+	/* Writing to the FRDA of CHANNEL.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
+
+	/* Writing to the COMMAND REG.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_INIT);
+
+	/* Initialize TxDMA.
+	 */
+	DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
+#if 0
+	printf("TX status = 0x%08X\n", v);
+#endif
+
+	/* Writing to the FRDA of CHANNEL.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
+
+	tx_new = rx_new = 0;
+
+	tx_hold = NUM_TX_DESC - 1;
+	rx_hold = NUM_RX_DESC - 1;
+
+#if 0
+	rx_ring[rx_hold].params.field.HOLD = 1;
+#endif
+	/* enable spanning tree forwarding, enable the CPU port */
+	/* ST_PT:
+	 *	CPS (CPU port status)	0x3 (forwarding)
+	 *	LPS (LAN port status)	0x3 (forwarding)
+	 *	PPS (PC port status)	0x3 (forwarding)
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
+
+#if 0
+	printf("Leaving inca_switch_init()\n");
+#endif
+
+	return 0;
+}
+
+
+static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	int		       i;
+	int		       res	= -1;
+	u32		       command;
+	u32		       regValue;
+	inca_tx_descriptor_t * tx_desc	= KSEG1ADDR(&tx_ring[tx_new]);
+
+#if 0
+	printf("Entered inca_switch_send()\n");
+#endif
+
+	if (length <= 0) {
+		printf ("%s: bad packet size: %d\n", dev->name, length);
+		goto Done;
+	}
+
+	for(i = 0; tx_desc->C == 0; i++) {
+		if (i >= TOUT_LOOP) {
+			printf("%s: tx error buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+
+	if (tx_old_hold >= 0) {
+		KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1;
+	}
+	tx_old_hold = tx_hold;
+
+	tx_desc->params.word =
+			(INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
+
+	tx_desc->C = 0;
+	tx_desc->TxDataPtr = (u32)packet;
+	tx_desc->params.field.NBA = length;
+
+	KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0;
+
+	tx_hold = tx_new;
+	tx_new	= (tx_new + 1) % NUM_TX_DESC;
+
+
+	if (! initialized) {
+		command = INCA_IP_DMA_DMA_TXCCR0_INIT;
+		initialized = 1;
+	} else {
+		command = INCA_IP_DMA_DMA_TXCCR0_HR;
+	}
+
+	DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
+	regValue |= command;
+#if 0
+	printf("regValue = 0x%x\n", regValue);
+#endif
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
+
+#if 1
+	for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++) {
+		if (i >= TOUT_LOOP) {
+			printf("%s: tx buffer not ready\n", dev->name);
+			goto Done;
+		}
+	}
+#endif
+	res = length;
+Done:
+#if 0
+	printf("Leaving inca_switch_send()\n");
+#endif
+	return res;
+}
+
+
+static int inca_switch_recv(struct eth_device *dev)
+{
+	int		       length  = 0;
+	inca_rx_descriptor_t * rx_desc;
+
+#if 0
+	printf("Entered inca_switch_recv()\n");
+#endif
+
+	for (;;) {
+		rx_desc = KSEG1ADDR(&rx_ring[rx_new]);
+
+		if (rx_desc->status.field.C == 0) {
+			break;
+		}
+
+#if 0
+		rx_ring[rx_new].params.field.HOLD = 1;
+#endif
+
+		if (! rx_desc->status.field.Eop) {
+			printf("Partly received packet!!!\n");
+			break;
+		}
+
+		length = rx_desc->status.field.NBT;
+		rx_desc->status.word &=
+			 ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C);
+#if 0
+{
+  int i;
+  for (i=0;i<length - 4;i++) {
+    if (i % 16 == 0) printf("\n%04x: ", i);
+    printf("%02X ", NetRxPackets[rx_new][i]);
+  }
+  printf("\n");
+}
+#endif
+
+		if (length) {
+#if 0
+			printf("Received %d bytes\n", length);
+#endif
+			NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]), length - 4);
+		} else {
+#if 1
+			printf("Zero length!!!\n");
+#endif
+		}
+
+
+		KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0;
+
+		rx_hold = rx_new;
+
+		rx_new = (rx_new + 1) % NUM_RX_DESC;
+	}
+
+#if 0
+	printf("Leaving inca_switch_recv()\n");
+#endif
+
+	return length;
+}
+
+
+static void inca_switch_halt(struct eth_device *dev)
+{
+#if 0
+	printf("Entered inca_switch_halt()\n");
+#endif
+
+#if 1
+	initialized = 0;
+#endif
+#if 1
+	/* Disable forwarding to the CPU port.
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
+
+	/* Close RxDMA channel.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
+
+	/* Close TxDMA channel.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
+
+
+#endif
+#if 0
+	printf("Leaving inca_switch_halt()\n");
+#endif
+}
+
+
+static void inca_init_switch_chip(void)
+{
+	u32 regValue;
+
+	/* To workaround a problem with collision counter
+	 * (see Errata sheet).
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
+	SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
+
+#if 1
+	/* init MDIO configuration:
+	 *	MDS (Poll speed):	0x01 (4ms)
+	 *	PHY_LAN_ADDR:		0x06
+	 *	PHY_PC_ADDR:		0x05
+	 *	UEP (Use External PHY): 0x00 (Internal PHY is used)
+	 *	PS (Port Select):	0x00 (PT/UMM for LAN)
+	 *	PT (PHY Test):		0x00 (no test mode)
+	 *	UMM (Use MDIO Mode):	0x00 (state machine is disabled)
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
+
+	/* init PHY:
+	 *	SL (Auto Neg. Speed for LAN)
+	 *	SP (Auto Neg. Speed for PC)
+	 *	LL (Link Status for LAN)
+	 *	LP (Link Status for PC)
+	 *	DL (Duplex Status for LAN)
+	 *	DP (Duplex Status for PC)
+	 *	PL (Auto Neg. Pause Status for LAN)
+	 *	PP (Auto Neg. Pause Status for PC)
+	 */
+	SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
+
+	/* MDIO_ACC:
+	 *	RA (Request/Ack)  0x01 (Request)
+	 *	RW (Read/Write)	  0x01 (Write)
+	 *	PHY_ADDR	  0x05 (PC)
+	 *	REG_ADDR	  0x00 (PHY_BCR: basic control register)
+	 *	PHY_DATA	  0x8000
+	 *		      Reset		      - software reset
+	 *		      LB (loop back)	      - normal
+	 *		      SS (speed select)	      - 10 Mbit/s
+	 *		      ANE (auto neg. enable)  - enable
+	 *		      PD (power down)	      - normal
+	 *		      ISO (isolate)	      - normal
+	 *		      RAN (restart auto neg.) - normal
+	 *		      DM (duplex mode)	      - half duplex
+	 *		      CT (collision test)     - enable
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a09000);
+
+	/* MDIO_ACC:
+	 *	RA (Request/Ack)  0x01 (Request)
+	 *	RW (Read/Write)	  0x01 (Write)
+	 *	PHY_ADDR	  0x06 (LAN)
+	 *	REG_ADDR	  0x00 (PHY_BCR: basic control register)
+	 *	PHY_DATA	  0x8000
+	 *		      Reset		      - software reset
+	 *		      LB (loop back)	      - normal
+	 *		      SS (speed select)	      - 10 Mbit/s
+	 *		      ANE (auto neg. enable)  - enable
+	 *		      PD (power down)	      - normal
+	 *		      ISO (isolate)	      - normal
+	 *		      RAN (restart auto neg.) - normal
+	 *		      DM (duplex mode)	      - half duplex
+	 *		      CT (collision test)     - enable
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c09000);
+
+#endif
+
+	/* Make sure the CPU port is disabled for now. We
+	 * don't want packets to get stacked for us until
+	 * we enable DMA and are prepared to receive them.
+	 */
+	SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
+
+	SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
+
+	/* CRC GEN is enabled.
+	 */
+	regValue |= 0x00000200;
+	SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
+
+	/* ADD TAG is disabled.
+	 */
+	SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
+	regValue &= ~0x00000002;
+	SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
+}
+
+
+static void inca_dma_init(void)
+{
+	/* Switch off all DMA channels.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF);
+
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF);
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF);
+
+	/* Setup TX channel polling time.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
+
+	/* Setup RX channel polling time.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
+
+	/* ERRATA: write reset value into the DMA RX IMR register.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
+
+	/* Just in case: disable all transmit interrupts also.
+	 */
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
+
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
+	DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);
+}
+
+#if defined(CONFIG_INCA_IP_SWITCH_AMDIX)
+static int inca_amdix(void)
+{
+	u32 phyReg1 = 0;
+	u32 phyReg4 = 0;
+	u32 phyReg5 = 0;
+	u32 phyReg6 = 0;
+	u32 phyReg31 = 0;
+	u32 regEphy = 0;
+	int mdi_flag;
+	int retries;
+
+	/* Setup GPIO pins.
+	 */
+	*INCA_IP_AUTO_MDIX_LAN_PORTS_DIR    |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
+	*INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
+
+#if 0
+	/* Wait for signal.
+	 */
+	retries = WAIT_SIGNAL_RETRIES;
+	while (--retries) {
+		SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+				(0x1 << 31) |	/* RA		*/
+				(0x0 << 30) |	/* Read		*/
+				(0x6 << 21) |	/* LAN		*/
+				(17  << 16));	/* PHY_MCSR	*/
+		do {
+			SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
+		} while (phyReg1 & (1 << 31));
+
+		if (phyReg1 & (1 << 1)) {
+			/* Signal detected */
+			break;
+		}
+	}
+
+	if (!retries)
+		goto Fail;
+#endif
+
+	/* Set MDI mode.
+	 */
+	*INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
+	mdi_flag = 1;
+
+	/* Wait for link.
+	 */
+	retries = WAIT_LINK_RETRIES;
+	while (--retries) {
+		udelay(LINK_RETRY_DELAY * 1000);
+		SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+				(0x1 << 31) |	/* RA		*/
+				(0x0 << 30) |	/* Read		*/
+				(0x6 << 21) |	/* LAN		*/
+				(1   << 16));	/* PHY_BSR	*/
+		do {
+			SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
+		} while (phyReg1 & (1 << 31));
+
+		if (phyReg1 & (1 << 2)) {
+			/* Link is up */
+			break;
+		} else if (mdi_flag) {
+			/* Set MDIX mode */
+			*INCA_IP_AUTO_MDIX_LAN_PORTS_OUT |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
+			mdi_flag = 0;
+		} else {
+			/* Set MDI mode */
+			*INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
+			mdi_flag = 1;
+		}
+	}
+
+	if (!retries) {
+		goto Fail;
+	} else {
+		SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+				(0x1 << 31) |	/* RA		*/
+				(0x0 << 30) |	/* Read		*/
+				(0x6 << 21) |	/* LAN		*/
+				(1   << 16));	/* PHY_BSR	*/
+		do {
+			SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
+		} while (phyReg1 & (1 << 31));
+
+		/* Auto-negotiation / Parallel detection complete
+		 */
+		if (phyReg1 & (1 << 5)) {
+			SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+				(0x1 << 31) |	/* RA		*/
+				(0x0 << 30) |	/* Read		*/
+				(0x6 << 21) |	/* LAN		*/
+				(31  << 16));	/* PHY_SCSR	*/
+			do {
+				SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg31);
+			} while (phyReg31 & (1 << 31));
+
+			switch ((phyReg31 >> 2) & 0x7) {
+			case INCA_SWITCH_PHY_SPEED_10H:
+				/* 10Base-T Half-duplex */
+				regEphy = 0;
+				break;
+			case INCA_SWITCH_PHY_SPEED_10F:
+				/* 10Base-T Full-duplex */
+				regEphy = INCA_IP_Switch_EPHY_DL;
+				break;
+			case INCA_SWITCH_PHY_SPEED_100H:
+				/* 100Base-TX Half-duplex */
+				regEphy = INCA_IP_Switch_EPHY_SL;
+				break;
+			case INCA_SWITCH_PHY_SPEED_100F:
+				/* 100Base-TX Full-duplex */
+				regEphy = INCA_IP_Switch_EPHY_SL | INCA_IP_Switch_EPHY_DL;
+				break;
+			}
+
+			/* In case of Auto-negotiation,
+			 * update the negotiated PAUSE support status
+			 */
+			if (phyReg1 & (1 << 3)) {
+				SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+					(0x1 << 31) |	/* RA		*/
+					(0x0 << 30) |	/* Read		*/
+					(0x6 << 21) |	/* LAN		*/
+					(6   << 16));	/* PHY_ANER	*/
+				do {
+					SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg6);
+				} while (phyReg6 & (1 << 31));
+
+				/* We are Autoneg-able.
+				 * Is Link partner also able to autoneg?
+				 */
+				if (phyReg6 & (1 << 0)) {
+					SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+						(0x1 << 31) |	/* RA		*/
+						(0x0 << 30) |	/* Read		*/
+						(0x6 << 21) |	/* LAN		*/
+						(4   << 16));	/* PHY_ANAR	*/
+					do {
+						SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg4);
+					} while (phyReg4 & (1 << 31));
+
+					/* We advertise PAUSE capab.
+					 * Does link partner also advertise it?
+					 */
+					if (phyReg4 & (1 << 10)) {
+						SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
+							(0x1 << 31) |	/* RA		*/
+							(0x0 << 30) |	/* Read		*/
+							(0x6 << 21) |	/* LAN		*/
+							(5   << 16));	/* PHY_ANLPAR	*/
+						do {
+							SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg5);
+						} while (phyReg5 & (1 << 31));
+
+						/* Link partner is PAUSE capab.
+						 */
+						if (phyReg5 & (1 << 10)) {
+							regEphy |= INCA_IP_Switch_EPHY_PL;
+						}
+					}
+				}
+
+			}
+
+			/* Link is up */
+			regEphy |= INCA_IP_Switch_EPHY_LL;
+
+			SW_WRITE_REG(INCA_IP_Switch_EPHY, regEphy);
+		}
+	}
+
+	return 0;
+
+Fail:
+	printf("No Link on LAN port\n");
+	return -1;
+}
+#endif /* CONFIG_INCA_IP_SWITCH_AMDIX */
+
+#endif
diff --git a/drivers/net/ks8695eth.c b/drivers/net/ks8695eth.c
new file mode 100644
index 0000000..b598dd7
--- /dev/null
+++ b/drivers/net/ks8695eth.c
@@ -0,0 +1,238 @@
+/*
+ * ks8695eth.c -- KS8695 ethernet driver
+ *
+ * (C) Copyright 2004-2005, Greg Ungerer <greg.ungerer@opengear.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/****************************************************************************/
+
+#include <common.h>
+
+#ifdef	CONFIG_DRIVER_KS8695ETH
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/arch/platform.h>
+
+/****************************************************************************/
+
+/*
+ * Hardware register access to the KS8695 LAN ethernet port
+ * (well, it is the 4 port switch really).
+ */
+#define	ks8695_read(a)    *((volatile unsigned long *) (KS8695_IO_BASE + (a)))
+#define	ks8695_write(a,v) *((volatile unsigned long *) (KS8695_IO_BASE + (a))) = (v)
+
+/****************************************************************************/
+
+/*
+ * Define the descriptor in-memory data structures.
+ */
+struct ks8695_txdesc {
+	uint32_t	owner;
+	uint32_t	ctrl;
+	uint32_t	addr;
+	uint32_t	next;
+};
+
+struct ks8695_rxdesc {
+	uint32_t	status;
+	uint32_t	ctrl;
+	uint32_t	addr;
+	uint32_t	next;
+};
+
+/****************************************************************************/
+
+/*
+ * Allocate local data structures to use for receiving and sending
+ * packets. Just to keep it all nice and simple.
+ */
+
+#define	TXDESCS		4
+#define	RXDESCS		4
+#define	BUFSIZE		2048
+
+volatile struct ks8695_txdesc ks8695_tx[TXDESCS] __attribute__((aligned(256)));
+volatile struct ks8695_rxdesc ks8695_rx[RXDESCS] __attribute__((aligned(256)));
+volatile uint8_t ks8695_bufs[BUFSIZE*(TXDESCS+RXDESCS)] __attribute__((aligned(2048)));;
+
+/****************************************************************************/
+
+/*
+ *	Ideally we want to use the MAC address stored in flash.
+ *	But we do some sanity checks in case they are not present
+ *	first.
+ */
+unsigned char eth_mac[] = {
+	0x00, 0x13, 0xc6, 0x00, 0x00, 0x00
+};
+
+void ks8695_getmac(void)
+{
+	unsigned char *fp;
+	int i;
+
+	/* Check if flash MAC is valid */
+	fp = (unsigned char *) 0x0201c000;
+	for (i = 0; (i < 6); i++) {
+		if ((fp[i] != 0) && (fp[i] != 0xff))
+			break;
+	}
+
+	/* If we found a valid looking MAC address then use it */
+	if (i < 6)
+		memcpy(&eth_mac[0], fp, 6);
+}
+
+/****************************************************************************/
+
+void eth_reset(bd_t *bd)
+{
+	int i;
+
+	debug ("%s(%d): eth_reset()\n", __FILE__, __LINE__);
+
+	/* Reset the ethernet engines first */
+	ks8695_write(KS8695_LAN_DMA_TX, 0x80000000);
+	ks8695_write(KS8695_LAN_DMA_RX, 0x80000000);
+
+	ks8695_getmac();
+
+	/* Set MAC address */
+	ks8695_write(KS8695_LAN_MAC_LOW, (eth_mac[5] | (eth_mac[4] << 8) |
+		(eth_mac[3] << 16) | (eth_mac[2] << 24)));
+	ks8695_write(KS8695_LAN_MAC_HIGH, (eth_mac[1] | (eth_mac[0] << 8)));
+
+	/* Turn the 4 port switch on */
+	i = ks8695_read(KS8695_SWITCH_CTRL0);
+	ks8695_write(KS8695_SWITCH_CTRL0, (i | 0x1));
+	/* ks8695_write(KS8695_WAN_CONTROL, 0x3f000066); */
+
+	/* Initialize descriptor rings */
+	for (i = 0; (i < TXDESCS); i++) {
+		ks8695_tx[i].owner = 0;
+		ks8695_tx[i].ctrl = 0;
+		ks8695_tx[i].addr = (uint32_t) &ks8695_bufs[i*BUFSIZE];
+		ks8695_tx[i].next = (uint32_t) &ks8695_tx[i+1];
+	}
+	ks8695_tx[TXDESCS-1].ctrl = 0x02000000;
+	ks8695_tx[TXDESCS-1].next = (uint32_t) &ks8695_tx[0];
+
+	for (i = 0; (i < RXDESCS); i++) {
+		ks8695_rx[i].status = 0x80000000;
+		ks8695_rx[i].ctrl = BUFSIZE - 4;
+		ks8695_rx[i].addr = (uint32_t) &ks8695_bufs[(i+TXDESCS)*BUFSIZE];
+		ks8695_rx[i].next = (uint32_t) &ks8695_rx[i+1];
+	}
+	ks8695_rx[RXDESCS-1].ctrl |= 0x00080000;
+	ks8695_rx[RXDESCS-1].next = (uint32_t) &ks8695_rx[0];
+
+	/* The KS8695 is pretty slow reseting the ethernets... */
+	udelay(2000000);
+
+	/* Enable the ethernet engine */
+	ks8695_write(KS8695_LAN_TX_LIST, (uint32_t) &ks8695_tx[0]);
+	ks8695_write(KS8695_LAN_RX_LIST, (uint32_t) &ks8695_rx[0]);
+	ks8695_write(KS8695_LAN_DMA_TX, 0x3);
+	ks8695_write(KS8695_LAN_DMA_RX, 0x71);
+	ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
+
+	printf("KS8695 ETHERNET: ");
+	for (i = 0; (i < 5); i++) {
+		bd->bi_enetaddr[i] = eth_mac[i];
+		printf("%02x:", eth_mac[i]);
+	}
+	bd->bi_enetaddr[i] = eth_mac[i];
+	printf("%02x\n", eth_mac[i]);
+}
+
+/****************************************************************************/
+
+int eth_init(bd_t *bd)
+{
+	debug ("%s(%d): eth_init()\n", __FILE__, __LINE__);
+
+	eth_reset(bd);
+	return 0;
+}
+
+/****************************************************************************/
+
+void eth_halt(void)
+{
+	debug ("%s(%d): eth_halt()\n", __FILE__, __LINE__);
+
+	/* Reset the ethernet engines */
+	ks8695_write(KS8695_LAN_DMA_TX, 0x80000000);
+	ks8695_write(KS8695_LAN_DMA_RX, 0x80000000);
+}
+
+/****************************************************************************/
+
+int eth_rx(void)
+{
+	volatile struct ks8695_rxdesc *dp;
+	int i, len = 0;
+
+	debug ("%s(%d): eth_rx()\n", __FILE__, __LINE__);
+
+	for (i = 0; (i < RXDESCS); i++) {
+		dp= &ks8695_rx[i];
+		if ((dp->status & 0x80000000) == 0) {
+			len = (dp->status & 0x7ff) - 4;
+			NetReceive((void *) dp->addr, len);
+			dp->status = 0x80000000;
+			ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
+			break;
+		}
+	}
+
+	return len;
+}
+
+/****************************************************************************/
+
+int eth_send(volatile void *packet, int len)
+{
+	volatile struct ks8695_txdesc *dp;
+	static int next = 0;
+
+	debug ("%s(%d): eth_send(packet=%x,len=%d)\n", __FILE__, __LINE__,
+		packet, len);
+
+	dp = &ks8695_tx[next];
+	memcpy((void *) dp->addr, (void *) packet, len);
+
+	if (len < 64) {
+		memset((void *) (dp->addr + len), 0, 64-len);
+		len = 64;
+	}
+
+	dp->ctrl = len | 0xe0000000;
+	dp->owner = 0x80000000;
+
+	ks8695_write(KS8695_LAN_DMA_TX, 0x3);
+	ks8695_write(KS8695_LAN_DMA_TX_START, 0x1);
+
+	if (++next >= TXDESCS)
+		next = 0;
+
+	return len;
+}
+
+#endif	/* CONFIG_DRIVER_KS8695ETH */
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
new file mode 100644
index 0000000..ecdcbd9
--- /dev/null
+++ b/drivers/net/lan91c96.c
@@ -0,0 +1,967 @@
+/*------------------------------------------------------------------------
+ * lan91c96.c
+ * This is a driver for SMSC's LAN91C96 single-chip Ethernet device, based
+ * on the SMC91111 driver from U-boot.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ *
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ *       Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC.  To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ *
+ * "Features" of the SMC chip:
+ *   6144 byte packet memory. ( for the 91C96 )
+ *   EEPROM for configuration
+ *   AUI/TP selection  ( mine has 10Base2/10BaseT select )
+ *
+ * Arguments:
+ * 	io	= for the base address
+ *	irq	= for the IRQ
+ *
+ * author:
+ * 	Erik Stahlman				( erik@vt.edu )
+ * 	Daris A Nevil				( dnevil@snmc.com )
+ *
+ *
+ * Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ *
+ * Sources:
+ *    o   SMSC LAN91C96 databook (www.smsc.com)
+ *    o   smc91111.c (u-boot driver)
+ *    o   smc9194.c (linux kernel driver)
+ *    o   lan91c96.c (Intel Diagnostic Manager driver)
+ *
+ * History:
+ * 	04/30/03  Mathijs Haarman	Modified smc91111.c (u-boot version)
+ *					for lan91c96
+ *---------------------------------------------------------------------------
+ */
+
+#include <common.h>
+#include <command.h>
+#include "lan91c96.h"
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_LAN91C96
+
+#if defined(CONFIG_CMD_NET)
+
+/*------------------------------------------------------------------------
+ *
+ * Configuration options, for the experienced user to change.
+ *
+ -------------------------------------------------------------------------*/
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN	0
+
+/*
+ * Wait time for memory to be free.  This probably shouldn't be
+ * tuned that much, as waiting for this means nothing else happens
+ * in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+#define SMC_DEBUG 0
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ *
+ * The internal workings of the driver.  If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ *
+ *------------------------------------------------------------------------
+ */
+#define CARDNAME "LAN91C96"
+
+#define SMC_BASE_ADDRESS CONFIG_LAN91C96_BASE
+
+#define SMC_DEV_NAME "LAN91C96"
+#define SMC_ALLOC_MAX_TRY 5
+#define SMC_TX_TIMEOUT 30
+
+#define ETH_ZLEN 60
+
+#ifdef  CONFIG_LAN91C96_USE_32_BIT
+#define USE_32_BIT  1
+#else
+#undef USE_32_BIT
+#endif
+
+/*-----------------------------------------------------------------
+ *
+ *  The driver can be entered at any of the following entry points.
+ *
+ *-----------------------------------------------------------------
+ */
+
+extern int eth_init (bd_t * bd);
+extern void eth_halt (void);
+extern int eth_rx (void);
+extern int eth_send (volatile void *packet, int length);
+#if 0
+static int smc_hw_init (void);
+#endif
+
+/*
+ * This is called by  register_netdev().  It is responsible for
+ * checking the portlist for the SMC9000 series chipset.  If it finds
+ * one, then it will initialize the device, find the hardware information,
+ * and sets up the appropriate device parameters.
+ * NOTE: Interrupts are *OFF* when this procedure is called.
+ *
+ * NB:This shouldn't be static since it is referred to externally.
+ */
+int smc_init (void);
+
+/*
+ * This is called by  unregister_netdev().  It is responsible for
+ * cleaning up before the driver is finally unregistered and discarded.
+ */
+void smc_destructor (void);
+
+/*
+ * The kernel calls this function when someone wants to use the device,
+ * typically 'ifconfig ethX up'.
+ */
+static int smc_open (bd_t *bd);
+
+
+/*
+ * This is called by the kernel in response to 'ifconfig ethX down'.  It
+ * is responsible for cleaning up everything that the open routine
+ * does, and maybe putting the card into a powerdown state.
+ */
+static int smc_close (void);
+
+/*
+ * This is a separate procedure to handle the receipt of a packet, to
+ * leave the interrupt code looking slightly cleaner
+ */
+static int smc_rcv (void);
+
+/* See if a MAC address is defined in the current environment. If so use it. If not
+ . print a warning and set the environment and other globals with the default.
+ . If an EEPROM is present it really should be consulted.
+*/
+int smc_get_ethaddr(bd_t *bd);
+int get_rom_mac(unsigned char *v_rom_mac);
+
+/* ------------------------------------------------------------
+ * Internal routines
+ * ------------------------------------------------------------
+ */
+
+static unsigned char smc_mac_addr[] = { 0xc0, 0x00, 0x00, 0x1b, 0x62, 0x9c };
+
+/*
+ * This function must be called before smc_open() if you want to override
+ * the default mac address.
+ */
+
+void smc_set_mac_addr (const unsigned char *addr)
+{
+	int i;
+
+	for (i = 0; i < sizeof (smc_mac_addr); i++) {
+		smc_mac_addr[i] = addr[i];
+	}
+}
+
+/*
+ * smc_get_macaddr is no longer used. If you want to override the default
+ * mac address, call smc_get_mac_addr as a part of the board initialisation.
+ */
+
+#if 0
+void smc_get_macaddr (byte * addr)
+{
+	/* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */
+	unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
+	int i;
+
+
+	for (i = 0; i < 6; i++) {
+		addr[0] = *(dnp1110_mac + 0);
+		addr[1] = *(dnp1110_mac + 1);
+		addr[2] = *(dnp1110_mac + 2);
+		addr[3] = *(dnp1110_mac + 3);
+		addr[4] = *(dnp1110_mac + 4);
+		addr[5] = *(dnp1110_mac + 5);
+	}
+}
+#endif /* 0 */
+
+/***********************************************
+ * Show available memory                       *
+ ***********************************************/
+void dump_memory_info (void)
+{
+	word mem_info;
+	word old_bank;
+
+	old_bank = SMC_inw (LAN91C96_BANK_SELECT) & 0xF;
+
+	SMC_SELECT_BANK (0);
+	mem_info = SMC_inw (LAN91C96_MIR);
+	PRINTK2 ("Memory: %4d available\n", (mem_info >> 8) * 2048);
+
+	SMC_SELECT_BANK (old_bank);
+}
+
+/*
+ * A rather simple routine to print out a packet for debugging purposes.
+ */
+#if SMC_DEBUG > 2
+static void print_packet (byte *, int);
+#endif
+
+/* #define tx_done(dev) 1 */
+
+
+/* this does a soft reset on the device */
+static void smc_reset (void);
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable (void);
+
+/* this puts the device in an inactive state */
+static void smc_shutdown (void);
+
+
+static int poll4int (byte mask, int timeout)
+{
+	int tmo = get_timer (0) + timeout * CFG_HZ;
+	int is_timeout = 0;
+	word old_bank = SMC_inw (LAN91C96_BANK_SELECT);
+
+	PRINTK2 ("Polling...\n");
+	SMC_SELECT_BANK (2);
+	while ((SMC_inw (LAN91C96_INT_STATS) & mask) == 0) {
+		if (get_timer (0) >= tmo) {
+			is_timeout = 1;
+			break;
+		}
+	}
+
+	/* restore old bank selection */
+	SMC_SELECT_BANK (old_bank);
+
+	if (is_timeout)
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * Function: smc_reset( void )
+ * Purpose:
+ *  	This sets the SMC91111 chip to its normal state, hopefully from whatever
+ * 	mess that any other DOS driver has put it in.
+ *
+ * Maybe I should reset more registers to defaults in here?  SOFTRST  should
+ * do that for me.
+ *
+ * Method:
+ *	1.  send a SOFT RESET
+ *	2.  wait for it to finish
+ *	3.  enable autorelease mode
+ *	4.  reset the memory management unit
+ *	5.  clear all interrupts
+ *
+*/
+static void smc_reset (void)
+{
+	PRINTK2 ("%s:smc_reset\n", SMC_DEV_NAME);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK (0);
+	SMC_outw (LAN91C96_RCR_SOFT_RST, LAN91C96_RCR);
+
+	udelay (10);
+
+	/* Disable transmit and receive functionality */
+	SMC_outw (0, LAN91C96_RCR);
+	SMC_outw (0, LAN91C96_TCR);
+
+	/* set the control register */
+	SMC_SELECT_BANK (1);
+	SMC_outw (SMC_inw (LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
+			  LAN91C96_CONTROL);
+
+	/* Disable all interrupts */
+	SMC_outb (0, LAN91C96_INT_MASK);
+}
+
+/*
+ * Function: smc_enable
+ * Purpose: let the chip talk to the outside work
+ * Method:
+ *	1.  Initialize the Memory Configuration Register
+ *	2.  Enable the transmitter
+ *	3.  Enable the receiver
+*/
+static void smc_enable ()
+{
+	PRINTK2 ("%s:smc_enable\n", SMC_DEV_NAME);
+	SMC_SELECT_BANK (0);
+
+	/* Initialize the Memory Configuration Register. See page
+	   49 of the LAN91C96 data sheet for details. */
+	SMC_outw (LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);
+
+	/* Initialize the Transmit Control Register */
+	SMC_outw (LAN91C96_TCR_TXENA, LAN91C96_TCR);
+	/* Initialize the Receive Control Register
+	 * FIXME:
+	 * The promiscuous bit set because I could not receive ARP reply
+	 * packets from the server when I send a ARP request. It only works
+	 * when I set the promiscuous bit
+	 */
+	SMC_outw (LAN91C96_RCR_RXEN | LAN91C96_RCR_PRMS, LAN91C96_RCR);
+}
+
+/*
+ * Function: smc_shutdown
+ * Purpose:  closes down the SMC91xxx chip.
+ * Method:
+ *	1. zero the interrupt mask
+ *	2. clear the enable receive flag
+ *	3. clear the enable xmit flags
+ *
+ * TODO:
+ *   (1) maybe utilize power down mode.
+ *	Why not yet?  Because while the chip will go into power down mode,
+ *	the manual says that it will wake up in response to any I/O requests
+ *	in the register space.   Empirical results do not show this working.
+ */
+static void smc_shutdown ()
+{
+	PRINTK2 (CARDNAME ":smc_shutdown\n");
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK (2);
+	SMC_outb (0, LAN91C96_INT_MASK);
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK (0);
+	SMC_outb (0, LAN91C96_RCR);
+	SMC_outb (0, LAN91C96_TCR);
+}
+
+
+/*
+ * Function:  smc_hardware_send_packet(struct net_device * )
+ * Purpose:
+ *	This sends the actual packet to the SMC9xxx chip.
+ *
+ * Algorithm:
+ * 	First, see if a saved_skb is available.
+ *		( this should NOT be called if there is no 'saved_skb'
+ *	Now, find the packet number that the chip allocated
+ *	Point the data pointers at it in memory
+ *	Set the length word in the chip's memory
+ *	Dump the packet to chip memory
+ *	Check if a last byte is needed ( odd length packet )
+ *		if so, set the control flag right
+ * 	Tell the card to send it
+ *	Enable the transmit interrupt, so I know if it failed
+ * 	Free the kernel data if I actually sent it.
+ */
+static int smc_send_packet (volatile void *packet, int packet_length)
+{
+	byte packet_no;
+	unsigned long ioaddr;
+	byte *buf;
+	int length;
+	int numPages;
+	int try = 0;
+	int time_out;
+	byte status;
+
+
+	PRINTK3 ("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);
+
+	length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
+
+	/* allocate memory
+	 ** The MMU wants the number of pages to be the number of 256 bytes
+	 ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	 **
+	 ** The 91C111 ignores the size bits, but the code is left intact
+	 ** for backwards and future compatibility.
+	 **
+	 ** Pkt size for allocating is data length +6 (for additional status
+	 ** words, length and ctl!)
+	 **
+	 ** If odd size then last byte is included in this header.
+	 */
+	numPages = ((length & 0xfffe) + 6);
+	numPages >>= 8;				/* Divide by 256 */
+
+	if (numPages > 7) {
+		printf ("%s: Far too big packet error. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* now, try to allocate the memory */
+
+	SMC_SELECT_BANK (2);
+	SMC_outw (LAN91C96_MMUCR_ALLOC_TX | numPages, LAN91C96_MMU);
+
+  again:
+	try++;
+	time_out = MEMORY_WAIT_TIME;
+	do {
+		status = SMC_inb (LAN91C96_INT_STATS);
+		if (status & LAN91C96_IST_ALLOC_INT) {
+
+			SMC_outb (LAN91C96_IST_ALLOC_INT, LAN91C96_INT_STATS);
+			break;
+		}
+	} while (--time_out);
+
+	if (!time_out) {
+		PRINTK2 ("%s: memory allocation, try %d failed ...\n",
+				 SMC_DEV_NAME, try);
+		if (try < SMC_ALLOC_MAX_TRY)
+			goto again;
+		else
+			return 0;
+	}
+
+	PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
+			 SMC_DEV_NAME, try);
+
+	/* I can send the packet now.. */
+
+	ioaddr = SMC_BASE_ADDRESS;
+
+	buf = (byte *) packet;
+
+	/* If I get here, I _know_ there is a packet slot waiting for me */
+	packet_no = SMC_inb (LAN91C96_ARR);
+	if (packet_no & LAN91C96_ARR_FAILED) {
+		/* or isn't there?  BAD CHIP! */
+		printf ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* we have a packet address, so tell the card to use it */
+	SMC_outb (packet_no, LAN91C96_PNR);
+
+	/* point to the beginning of the packet */
+	SMC_outw (LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+	PRINTK3 ("%s: Trying to xmit packet of length %x\n",
+			 SMC_DEV_NAME, length);
+
+#if SMC_DEBUG > 2
+	printf ("Transmitting Packet\n");
+	print_packet (buf, length);
+#endif
+
+	/* send the packet length ( +6 for status, length and ctl byte )
+	   and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+	SMC_outl ((length + 6) << 16, LAN91C96_DATA_HIGH);
+#else
+	SMC_outw (0, LAN91C96_DATA_HIGH);
+	/* send the packet length ( +6 for status words, length, and ctl */
+	SMC_outw ((length + 6), LAN91C96_DATA_HIGH);
+#endif /* USE_32_BIT */
+
+	/* send the actual data
+	 * I _think_ it's faster to send the longs first, and then
+	 * mop up by sending the last word.  It depends heavily
+	 * on alignment, at least on the 486.  Maybe it would be
+	 * a good idea to check which is optimal?  But that could take
+	 * almost as much time as is saved?
+	 */
+#ifdef USE_32_BIT
+	SMC_outsl (LAN91C96_DATA_HIGH, buf, length >> 2);
+	if (length & 0x2)
+		SMC_outw (*((word *) (buf + (length & 0xFFFFFFFC))),
+				  LAN91C96_DATA_HIGH);
+#else
+	SMC_outsw (LAN91C96_DATA_HIGH, buf, (length) >> 1);
+#endif /* USE_32_BIT */
+
+	/* Send the last byte, if there is one.   */
+	if ((length & 1) == 0) {
+		SMC_outw (0, LAN91C96_DATA_HIGH);
+	} else {
+		SMC_outw (buf[length - 1] | 0x2000, LAN91C96_DATA_HIGH);
+	}
+
+	/* and let the chipset deal with it */
+	SMC_outw (LAN91C96_MMUCR_ENQUEUE, LAN91C96_MMU);
+
+	/* poll for TX INT */
+	if (poll4int (LAN91C96_MSK_TX_INT, SMC_TX_TIMEOUT)) {
+		/* sending failed */
+		PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
+
+		/* release packet */
+		SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+
+
+		return 0;
+	} else {
+		/* ack. int */
+		SMC_outw (LAN91C96_IST_TX_INT, LAN91C96_INT_STATS);
+
+		PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME, length);
+
+		/* release packet */
+		SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+	}
+
+	return length;
+}
+
+/*-------------------------------------------------------------------------
+ * smc_destructor( struct net_device * dev )
+ *   Input parameters:
+ *	dev, pointer to the device structure
+ *
+ *   Output:
+ *	None.
+ *--------------------------------------------------------------------------
+ */
+void smc_destructor ()
+{
+	PRINTK2 (CARDNAME ":smc_destructor\n");
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open (bd_t *bd)
+{
+	int i, err;			/* used to set hw ethernet address */
+
+	PRINTK2 ("%s:smc_open\n", SMC_DEV_NAME);
+
+	/* reset the hardware */
+
+	smc_reset ();
+	smc_enable ();
+
+	SMC_SELECT_BANK (1);
+
+	err = smc_get_ethaddr (bd);	/* set smc_mac_addr, and sync it with u-boot globals */
+	if (err < 0) {
+		memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
+		return (-1);	/* upper code ignores this, but NOT bi_enetaddr */
+	}
+#ifdef USE_32_BIT
+	for (i = 0; i < 6; i += 2) {
+		word address;
+
+		address = smc_mac_addr[i + 1] << 8;
+		address |= smc_mac_addr[i];
+		SMC_outw (address, LAN91C96_IA0 + i);
+	}
+#else
+	for (i = 0; i < 6; i++)
+		SMC_outb (smc_mac_addr[i], LAN91C96_IA0 + i);
+#endif
+	return 0;
+}
+
+/*-------------------------------------------------------------
+ *
+ * smc_rcv -  receive a packet from the card
+ *
+ * There is ( at least ) a packet waiting to be read from
+ * chip-memory.
+ *
+ * o Read the status
+ * o If an error, record it
+ * o otherwise, read in the packet
+ *-------------------------------------------------------------
+ */
+static int smc_rcv ()
+{
+	int packet_number;
+	word status;
+	word packet_length;
+	int is_error = 0;
+
+#ifdef USE_32_BIT
+	dword stat_len;
+#endif
+
+
+	SMC_SELECT_BANK (2);
+	packet_number = SMC_inw (LAN91C96_FIFO);
+
+	if (packet_number & LAN91C96_FIFO_RXEMPTY) {
+		return 0;
+	}
+
+	PRINTK3 ("%s:smc_rcv\n", SMC_DEV_NAME);
+	/*  start reading from the start of the packet */
+	SMC_outw (LAN91C96_PTR_READ | LAN91C96_PTR_RCV |
+			  LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+	/* First two words are status and packet_length */
+#ifdef USE_32_BIT
+	stat_len = SMC_inl (LAN91C96_DATA_HIGH);
+	status = stat_len & 0xffff;
+	packet_length = stat_len >> 16;
+#else
+	status = SMC_inw (LAN91C96_DATA_HIGH);
+	packet_length = SMC_inw (LAN91C96_DATA_HIGH);
+#endif
+
+	packet_length &= 0x07ff;	/* mask off top bits */
+
+	PRINTK2 ("RCV: STATUS %4x LENGTH %4x\n", status, packet_length);
+
+	if (!(status & FRAME_FILTER)) {
+		/* Adjust for having already read the first two words */
+		packet_length -= 4;		/*4; */
+
+
+		/* set odd length for bug in LAN91C111, */
+		/* which never sets RS_ODDFRAME */
+		/* TODO ? */
+
+
+#ifdef USE_32_BIT
+		PRINTK3 (" Reading %d dwords (and %d bytes) \n",
+			 packet_length >> 2, packet_length & 3);
+		/* QUESTION:  Like in the TX routine, do I want
+		   to send the DWORDs or the bytes first, or some
+		   mixture.  A mixture might improve already slow PIO
+		   performance  */
+		SMC_insl (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 2);
+		/* read the left over bytes */
+		if (packet_length & 3) {
+			int i;
+
+			byte *tail = (byte *) (NetRxPackets[0] + (packet_length & ~3));
+			dword leftover = SMC_inl (LAN91C96_DATA_HIGH);
+
+			for (i = 0; i < (packet_length & 3); i++)
+				*tail++ = (byte) (leftover >> (8 * i)) & 0xff;
+		}
+#else
+		PRINTK3 (" Reading %d words and %d byte(s) \n",
+				 (packet_length >> 1), packet_length & 1);
+		SMC_insw (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 1);
+
+#endif /* USE_32_BIT */
+
+#if	SMC_DEBUG > 2
+		printf ("Receiving Packet\n");
+		print_packet (NetRxPackets[0], packet_length);
+#endif
+	} else {
+		/* error ... */
+		/* TODO ? */
+		is_error = 1;
+	}
+
+	while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+		udelay (1);		/* Wait until not busy */
+
+	/*  error or good, tell the card to get rid of this packet */
+	SMC_outw (LAN91C96_MMUCR_RELEASE_RX, LAN91C96_MMU);
+
+	while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+		udelay (1);		/* Wait until not busy */
+
+	if (!is_error) {
+		/* Pass the packet up to the protocol layers. */
+		NetReceive (NetRxPackets[0], packet_length);
+		return packet_length;
+	} else {
+		return 0;
+	}
+
+}
+
+/*----------------------------------------------------
+ * smc_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ *
+ -----------------------------------------------------*/
+static int smc_close ()
+{
+	PRINTK2 ("%s:smc_close\n", SMC_DEV_NAME);
+
+	/* clear everything */
+	smc_shutdown ();
+
+	return 0;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet (byte * buf, int length)
+{
+#if 0
+	int i;
+	int remainder;
+	int lines;
+
+	printf ("Packet of length %d \n", length);
+
+	lines = length / 16;
+	remainder = length % 16;
+
+	for (i = 0; i < lines; i++) {
+		int cur;
+
+		for (cur = 0; cur < 8; cur++) {
+			byte a, b;
+
+			a = *(buf++);
+			b = *(buf++);
+			printf ("%02x%02x ", a, b);
+		}
+		printf ("\n");
+	}
+	for (i = 0; i < remainder / 2; i++) {
+		byte a, b;
+
+		a = *(buf++);
+		b = *(buf++);
+		printf ("%02x%02x ", a, b);
+	}
+	printf ("\n");
+#endif /* 0 */
+}
+#endif /* SMC_DEBUG > 2 */
+
+int eth_init (bd_t * bd)
+{
+	return (smc_open(bd));
+}
+
+void eth_halt ()
+{
+	smc_close ();
+}
+
+int eth_rx ()
+{
+	return smc_rcv ();
+}
+
+int eth_send (volatile void *packet, int length)
+{
+	return smc_send_packet (packet, length);
+}
+
+
+#if 0
+/*-------------------------------------------------------------------------
+ * smc_hw_init()
+ *
+ *   Function:
+ *      Reset and enable the device, check if the I/O space location
+ *      is correct
+ *
+ *   Input parameters:
+ *      None
+ *
+ *   Output:
+ *	0 --> success
+ *	1 --> error
+ *--------------------------------------------------------------------------
+ */
+static int smc_hw_init ()
+{
+	unsigned short status_test;
+
+	/* The attribute register of the LAN91C96 is located at address
+	   0x0e000000 on the lubbock platform */
+	volatile unsigned *attaddr = (unsigned *) (0x0e000000);
+
+	/* first reset, then enable the device. Sequence is critical */
+	attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_SRESET;
+	udelay (100);
+	attaddr[LAN91C96_ECOR] &= ~LAN91C96_ECOR_SRESET;
+	attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_ENABLE;
+
+	/* force 16-bit mode */
+	attaddr[LAN91C96_ECSR] &= ~LAN91C96_ECSR_IOIS8;
+	udelay (100);
+
+	/* check if the I/O address is correct, the upper byte of the
+	   bank select register should read 0x33 */
+
+	status_test = SMC_inw (LAN91C96_BANK_SELECT);
+	if ((status_test & 0xFF00) != 0x3300) {
+		printf ("Failed to initialize ethernetchip\n");
+		return 1;
+	}
+	return 0;
+}
+#endif /* 0 */
+
+#endif /* COMMANDS & CFG_NET */
+
+
+/* smc_get_ethaddr (bd_t * bd)
+ *
+ * This checks both the environment and the ROM for an ethernet address. If
+ * found, the environment takes precedence.
+ */
+
+int smc_get_ethaddr (bd_t * bd)
+{
+	int env_size = 0;
+	int rom_valid = 0;
+	int env_present = 0;
+	int reg = 0;
+	char *s = NULL;
+	char *e = NULL;
+	char *v_mac, es[] = "11:22:33:44:55:66";
+	char s_env_mac[64];
+	uchar v_env_mac[6];
+	uchar v_rom_mac[6];
+
+	env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
+	if (env_size != sizeof(es)) {	/* Ignore if env is bad or not set */
+		printf ("\n*** Warning: ethaddr is not set properly, ignoring!!\n");
+	} else {
+		env_present = 1;
+		s = s_env_mac;
+
+		for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
+			v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
+			if (s)
+				s = (*e) ? e + 1 : e;
+		}
+	}
+
+	rom_valid = get_rom_mac (v_rom_mac);	/* get ROM mac value if any */
+
+	if (!env_present) {	/* if NO env */
+		if (rom_valid) {	/* but ROM is valid */
+			v_mac = (char *)v_rom_mac;
+			sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
+				 v_mac[0], v_mac[1], v_mac[2], v_mac[3],
+				 v_mac[4], v_mac[5]);
+			setenv ("ethaddr", s_env_mac);
+		} else {	/* no env, bad ROM */
+			printf ("\n*** ERROR: ethaddr is NOT set !!\n");
+			return (-1);
+		}
+	} else {		/* good env, don't care ROM */
+		v_mac = (char *)v_env_mac;	/* always use a good env over a ROM */
+	}
+
+	if (env_present && rom_valid) { /* if both env and ROM are good */
+		if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
+			printf ("\nWarning: MAC addresses don't match:\n");
+			printf ("\tHW MAC address:  "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				v_rom_mac[0], v_rom_mac[1],
+				v_rom_mac[2], v_rom_mac[3],
+				v_rom_mac[4], v_rom_mac[5] );
+			printf ("\t\"ethaddr\" value: "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				v_env_mac[0], v_env_mac[1],
+				v_env_mac[2], v_env_mac[3],
+				v_env_mac[4], v_env_mac[5]) ;
+			debug ("### Set MAC addr from environment\n");
+		}
+	}
+	memcpy (bd->bi_enetaddr, v_mac, 6);	/* update global address to match env (allows env changing) */
+	smc_set_mac_addr ((unsigned char *)v_mac); /* use old function to update smc default */
+	PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
+		v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
+	return (0);
+}
+
+/*
+ * get_rom_mac()
+ * Note, this has omly been tested for the OMAP730 P2.
+ */
+
+int get_rom_mac (unsigned char *v_rom_mac)
+{
+#ifdef HARDCODE_MAC	/* used for testing or to supress run time warnings */
+	char hw_mac_addr[] = { 0x02, 0x80, 0xad, 0x20, 0x31, 0xb8 };
+
+	memcpy (v_rom_mac, hw_mac_addr, 6);
+	return (1);
+#else
+	int i;
+	SMC_SELECT_BANK (1);
+	for (i=0; i<6; i++)
+	{
+		v_rom_mac[i] = SMC_inb (LAN91C96_IA0 + i);
+	}
+	return (1);
+#endif
+}
+
+#endif /* CONFIG_DRIVER_LAN91C96 */
diff --git a/drivers/net/lan91c96.h b/drivers/net/lan91c96.h
new file mode 100644
index 0000000..7d33a82
--- /dev/null
+++ b/drivers/net/lan91c96.h
@@ -0,0 +1,643 @@
+/*------------------------------------------------------------------------
+ * lan91c96.h
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ *       Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This file contains register information and access macros for
+ * the LAN91C96 single chip ethernet controller.  It is a modified
+ * version of the smc9111.h file.
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC. To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ * Authors
+ * 	Erik Stahlman				( erik@vt.edu )
+ *	Daris A Nevil				( dnevil@snmc.com )
+ *
+ * History
+ * 04/30/03	Mathijs Haarman		Modified smc91111.h (u-boot version)
+ *		                        for lan91c96
+ *-------------------------------------------------------------------------
+ */
+#ifndef _LAN91C96_H_
+#define _LAN91C96_H_
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+/*
+ * This function may be called by the board specific initialisation code
+ * in order to override the default mac address.
+ */
+
+void smc_set_mac_addr(const unsigned char *addr);
+
+
+/* I want some simple types */
+
+typedef unsigned char			byte;
+typedef unsigned short			word;
+typedef unsigned long int 		dword;
+
+/*
+ * DEBUGGING LEVELS
+ *
+ * 0 for normal operation
+ * 1 for slightly more details
+ * >2 for various levels of increasingly useless information
+ *    2 for interrupt tracking, status flags
+ *    3 for packet info
+ *    4 for complete packet dumps
+ */
+/*#define SMC_DEBUG 0 */
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define	SMC_IO_EXTENT	16
+
+#ifdef CONFIG_PXA250
+
+#ifdef	CONFIG_LUBBOCK
+#define	SMC_IO_SHIFT	2
+#undef	USE_32_BIT
+
+#else
+#define	SMC_IO_SHIFT	0
+#endif
+
+#define	SMCREG(r)	(SMC_BASE_ADDRESS+((r)<<SMC_IO_SHIFT))
+
+#define	SMC_inl(r) 	(*((volatile dword *)SMCREG(r)))
+#define	SMC_inw(r) 	(*((volatile word *)SMCREG(r)))
+#define SMC_inb(p) ({ \
+	unsigned int __p = p; \
+	unsigned int __v = SMC_inw(__p & ~1); \
+	if (__p & 1) __v >>= 8; \
+	else __v &= 0xff; \
+	__v; })
+
+#define	SMC_outl(d,r)	(*((volatile dword *)SMCREG(r)) = d)
+#define	SMC_outw(d,r)	(*((volatile word *)SMCREG(r)) = d)
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+
+#define SMC_outsl(r,b,l)	({	int __i; \
+					dword *__b2; \
+					__b2 = (dword *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outl( *(__b2 + __i), r ); \
+					} \
+				})
+
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r ); \
+					} \
+				})
+
+#define SMC_insl(r,b,l) 	({	int __i ;  \
+					dword *__b2;  \
+					__b2 = (dword *) b;  \
+					for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inl(r);  \
+					  SMC_inl(0);  \
+					};  \
+				})
+
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+					__b2 = (word *) b;  \
+					for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+
+#define SMC_insb(r,b,l) 	({	int __i ;  \
+					byte *__b2;  \
+					__b2 = (byte *) b;  \
+					for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inb(r);  \
+					  SMC_inb(0);  \
+					};  \
+				})
+
+#else /* if not CONFIG_PXA250 */
+
+/*
+ * We have only 16 Bit PCMCIA access on Socket 0
+ */
+
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+(r))))
+#define  SMC_inb(r)	(((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF)
+
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d)
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+#if 0
+#define	SMC_outsw(r,b,l)	outsw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r); \
+					} \
+				})
+#endif
+
+#if 0
+#define	SMC_insw(r,b,l) 	insw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+					__b2 = (word *) b;  \
+					for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+#endif
+
+#endif
+
+/*
+ ****************************************************************************
+ *	Bank Select Field
+ ****************************************************************************
+ */
+#define LAN91C96_BANK_SELECT  14       /* Bank Select Register */
+#define LAN91C96_BANKSELECT (0x3UC << 0)
+#define BANK0               0x00
+#define BANK1               0x01
+#define BANK2               0x02
+#define BANK3               0x03
+#define BANK4               0x04
+
+/*
+ ****************************************************************************
+ *	EEPROM Addresses.
+ ****************************************************************************
+ */
+#define EEPROM_MAC_OFFSET_1    0x6020
+#define EEPROM_MAC_OFFSET_2    0x6021
+#define EEPROM_MAC_OFFSET_3    0x6022
+
+/*
+ ****************************************************************************
+ *	Bank 0 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_TCR          0        /* Transmit Control Register */
+#define LAN91C96_EPH_STATUS   2        /* EPH Status Register */
+#define LAN91C96_RCR          4        /* Receive Control Register */
+#define LAN91C96_COUNTER      6        /* Counter Register */
+#define LAN91C96_MIR          8        /* Memory Information Register */
+#define LAN91C96_MCR          10       /* Memory Configuration Register */
+
+/*
+ ****************************************************************************
+ *	Transmit Control Register - Bank 0 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_TCR_TXENA        (0x1U << 0)
+#define LAN91C96_TCR_LOOP         (0x1U << 1)
+#define LAN91C96_TCR_FORCOL       (0x1U << 2)
+#define LAN91C96_TCR_TXP_EN       (0x1U << 3)
+#define LAN91C96_TCR_PAD_EN       (0x1U << 7)
+#define LAN91C96_TCR_NOCRC        (0x1U << 8)
+#define LAN91C96_TCR_MON_CSN      (0x1U << 10)
+#define LAN91C96_TCR_FDUPLX       (0x1U << 11)
+#define LAN91C96_TCR_STP_SQET     (0x1U << 12)
+#define LAN91C96_TCR_EPH_LOOP     (0x1U << 13)
+#define LAN91C96_TCR_ETEN_TYPE    (0x1U << 14)
+#define LAN91C96_TCR_FDSE         (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	EPH Status Register - Bank 0 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_EPHSR_TX_SUC     (0x1U << 0)
+#define LAN91C96_EPHSR_SNGL_COL   (0x1U << 1)
+#define LAN91C96_EPHSR_MUL_COL    (0x1U << 2)
+#define LAN91C96_EPHSR_LTX_MULT   (0x1U << 3)
+#define LAN91C96_EPHSR_16COL      (0x1U << 4)
+#define LAN91C96_EPHSR_SQET       (0x1U << 5)
+#define LAN91C96_EPHSR_LTX_BRD    (0x1U << 6)
+#define LAN91C96_EPHSR_TX_DEFR    (0x1U << 7)
+#define LAN91C96_EPHSR_WAKEUP     (0x1U << 8)
+#define LAN91C96_EPHSR_LATCOL     (0x1U << 9)
+#define LAN91C96_EPHSR_LOST_CARR  (0x1U << 10)
+#define LAN91C96_EPHSR_EXC_DEF    (0x1U << 11)
+#define LAN91C96_EPHSR_CTR_ROL    (0x1U << 12)
+
+#define LAN91C96_EPHSR_LINK_OK    (0x1U << 14)
+#define LAN91C96_EPHSR_TX_UNRN    (0x1U << 15)
+
+#define LAN91C96_EPHSR_ERRORS     (LAN91C96_EPHSR_SNGL_COL  |    \
+				   LAN91C96_EPHSR_MUL_COL   |    \
+				   LAN91C96_EPHSR_16COL     |    \
+				   LAN91C96_EPHSR_SQET      |    \
+				   LAN91C96_EPHSR_TX_DEFR   |    \
+				   LAN91C96_EPHSR_LATCOL    |    \
+				   LAN91C96_EPHSR_LOST_CARR |    \
+				   LAN91C96_EPHSR_EXC_DEF   |    \
+				   LAN91C96_EPHSR_LINK_OK   |    \
+				   LAN91C96_EPHSR_TX_UNRN)
+
+/*
+ ****************************************************************************
+ *	Receive Control Register - Bank 0 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_RCR_RX_ABORT     (0x1U << 0)
+#define LAN91C96_RCR_PRMS         (0x1U << 1)
+#define LAN91C96_RCR_ALMUL        (0x1U << 2)
+#define LAN91C96_RCR_RXEN         (0x1U << 8)
+#define LAN91C96_RCR_STRIP_CRC    (0x1U << 9)
+#define LAN91C96_RCR_FILT_CAR     (0x1U << 14)
+#define LAN91C96_RCR_SOFT_RST     (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	Counter Register - Bank 0 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_ECR_SNGL_COL     (0xFU << 0)
+#define LAN91C96_ECR_MULT_COL     (0xFU << 5)
+#define LAN91C96_ECR_DEF_TX       (0xFU << 8)
+#define LAN91C96_ECR_EXC_DEF_TX   (0xFU << 12)
+
+/*
+ ****************************************************************************
+ *	Memory Information Register - Bank 0 - OFfset 8
+ ****************************************************************************
+ */
+#define LAN91C96_MIR_SIZE        (0x18 << 0)    /* 6144 bytes */
+
+/*
+ ****************************************************************************
+ *	Memory Configuration Register - Bank 0 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_MCR_MEM_RES      (0xFFU << 0)
+#define LAN91C96_MCR_MEM_MULT     (0x3U << 9)
+#define LAN91C96_MCR_HIGH_ID      (0x3U << 12)
+
+#define LAN91C96_MCR_TRANSMIT_PAGES 0x6
+
+/*
+ ****************************************************************************
+ *	Bank 1 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_CONFIG       0        /* Configuration Register */
+#define LAN91C96_BASE         2        /* Base Address Register */
+#define LAN91C96_IA0          4        /* Individual Address Register - 0 */
+#define LAN91C96_IA1          5        /* Individual Address Register - 1 */
+#define LAN91C96_IA2          6        /* Individual Address Register - 2 */
+#define LAN91C96_IA3          7        /* Individual Address Register - 3 */
+#define LAN91C96_IA4          8        /* Individual Address Register - 4 */
+#define LAN91C96_IA5          9        /* Individual Address Register - 5 */
+#define LAN91C96_GEN_PURPOSE  10       /* General Address Registers */
+#define LAN91C96_CONTROL      12       /* Control Register */
+
+/*
+ ****************************************************************************
+ *	Configuration Register - Bank 1 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_CR_INT_SEL0      (0x1U << 1)
+#define LAN91C96_CR_INT_SEL1      (0x1U << 2)
+#define LAN91C96_CR_RES           (0x3U << 3)
+#define LAN91C96_CR_DIS_LINK      (0x1U << 6)
+#define LAN91C96_CR_16BIT         (0x1U << 7)
+#define LAN91C96_CR_AUI_SELECT    (0x1U << 8)
+#define LAN91C96_CR_SET_SQLCH     (0x1U << 9)
+#define LAN91C96_CR_FULL_STEP     (0x1U << 10)
+#define LAN91C96_CR_NO_WAIT       (0x1U << 12)
+
+/*
+ ****************************************************************************
+ *	Base Address Register - Bank 1 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_BAR_RA_BITS      (0x27U << 0)
+#define LAN91C96_BAR_ROM_SIZE     (0x1U << 6)
+#define LAN91C96_BAR_A_BITS       (0xFFU << 8)
+
+/*
+ ****************************************************************************
+ *	Control Register - Bank 1 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_CTR_STORE        (0x1U << 0)
+#define LAN91C96_CTR_RELOAD       (0x1U << 1)
+#define LAN91C96_CTR_EEPROM       (0x1U << 2)
+#define LAN91C96_CTR_TE_ENABLE    (0x1U << 5)
+#define LAN91C96_CTR_CR_ENABLE    (0x1U << 6)
+#define LAN91C96_CTR_LE_ENABLE    (0x1U << 7)
+#define LAN91C96_CTR_BIT_8        (0x1U << 8)
+#define LAN91C96_CTR_AUTO_RELEASE (0x1U << 11)
+#define LAN91C96_CTR_WAKEUP_EN    (0x1U << 12)
+#define LAN91C96_CTR_PWRDN        (0x1U << 13)
+#define LAN91C96_CTR_RCV_BAD      (0x1U << 14)
+
+/*
+ ****************************************************************************
+ *	Bank 2 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_MMU            0      /* MMU Command Register */
+#define LAN91C96_AUTO_TX_START  1      /* Auto Tx Start Register */
+#define LAN91C96_PNR            2      /* Packet Number Register */
+#define LAN91C96_ARR            3      /* Allocation Result Register */
+#define LAN91C96_FIFO           4      /* FIFO Ports Register */
+#define LAN91C96_POINTER        6      /* Pointer Register */
+#define LAN91C96_DATA_HIGH      8      /* Data High Register */
+#define LAN91C96_DATA_LOW       10     /* Data Low Register */
+#define LAN91C96_INT_STATS      12     /* Interrupt Status Register - RO */
+#define LAN91C96_INT_ACK        12     /* Interrupt Acknowledge Register -WO */
+#define LAN91C96_INT_MASK       13     /* Interrupt Mask Register */
+
+/*
+ ****************************************************************************
+ *	MMU Command Register - Bank 2 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_MMUCR_NO_BUSY    (0x1U << 0)
+#define LAN91C96_MMUCR_N1         (0x1U << 1)
+#define LAN91C96_MMUCR_N2         (0x1U << 2)
+#define LAN91C96_MMUCR_COMMAND    (0xFU << 4)
+#define LAN91C96_MMUCR_ALLOC_TX   (0x2U << 4)    /* WXYZ = 0010 */
+#define LAN91C96_MMUCR_RESET_MMU  (0x4U << 4)    /* WXYZ = 0100 */
+#define LAN91C96_MMUCR_REMOVE_RX  (0x6U << 4)    /* WXYZ = 0110 */
+#define LAN91C96_MMUCR_REMOVE_TX  (0x7U << 4)    /* WXYZ = 0111 */
+#define LAN91C96_MMUCR_RELEASE_RX (0x8U << 4)    /* WXYZ = 1000 */
+#define LAN91C96_MMUCR_RELEASE_TX (0xAU << 4)    /* WXYZ = 1010 */
+#define LAN91C96_MMUCR_ENQUEUE    (0xCU << 4)    /* WXYZ = 1100 */
+#define LAN91C96_MMUCR_RESET_TX   (0xEU << 4)    /* WXYZ = 1110 */
+
+/*
+ ****************************************************************************
+ *	Auto Tx Start Register - Bank 2 - Offset 1
+ ****************************************************************************
+ */
+#define LAN91C96_AUTOTX           (0xFFU << 0)
+
+/*
+ ****************************************************************************
+ *	Packet Number Register - Bank 2 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_PNR_TX           (0x1FU << 0)
+
+/*
+ ****************************************************************************
+ *	Allocation Result Register - Bank 2 - Offset 3
+ ****************************************************************************
+ */
+#define LAN91C96_ARR_ALLOC_PN     (0x7FU << 0)
+#define LAN91C96_ARR_FAILED       (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	FIFO Ports Register - Bank 2 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_FIFO_TX_DONE_PN  (0x1FU << 0)
+#define LAN91C96_FIFO_TEMPTY      (0x1U << 7)
+#define LAN91C96_FIFO_RX_DONE_PN  (0x1FU << 8)
+#define LAN91C96_FIFO_RXEMPTY     (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	Pointer Register - Bank 2 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_PTR_LOW          (0xFFU << 0)
+#define LAN91C96_PTR_HIGH         (0x7U << 8)
+#define LAN91C96_PTR_AUTO_TX      (0x1U << 11)
+#define LAN91C96_PTR_ETEN         (0x1U << 12)
+#define LAN91C96_PTR_READ         (0x1U << 13)
+#define LAN91C96_PTR_AUTO_INCR    (0x1U << 14)
+#define LAN91C96_PTR_RCV          (0x1U << 15)
+
+#define LAN91C96_PTR_RX_FRAME     (LAN91C96_PTR_RCV       |    \
+				   LAN91C96_PTR_AUTO_INCR |    \
+				   LAN91C96_PTR_READ)
+
+/*
+ ****************************************************************************
+ *	Data Register - Bank 2 - Offset 8
+ ****************************************************************************
+ */
+#define LAN91C96_CONTROL_CRC      (0x1U << 4)    /* CRC bit */
+#define LAN91C96_CONTROL_ODD      (0x1U << 5)    /* ODD bit */
+
+/*
+ ****************************************************************************
+ *	Interrupt Status Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_IST_RCV_INT      (0x1U << 0)
+#define LAN91C96_IST_TX_INT       (0x1U << 1)
+#define LAN91C96_IST_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_IST_ALLOC_INT    (0x1U << 3)
+#define LAN91C96_IST_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_IST_EPH_INT      (0x1U << 5)
+#define LAN91C96_IST_ERCV_INT     (0x1U << 6)
+#define LAN91C96_IST_RX_IDLE_INT  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	Interrupt Acknowledge Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ACK_TX_INT       (0x1U << 1)
+#define LAN91C96_ACK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_ACK_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_ACK_ERCV_INT     (0x1U << 6)
+
+/*
+ ****************************************************************************
+ *	Interrupt Mask Register - Bank 2 - Offset 13
+ ****************************************************************************
+ */
+#define LAN91C96_MSK_RCV_INT      (0x1U << 0)
+#define LAN91C96_MSK_TX_INT       (0x1U << 1)
+#define LAN91C96_MSK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_MSK_ALLOC_INT    (0x1U << 3)
+#define LAN91C96_MSK_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_MSK_EPH_INT      (0x1U << 5)
+#define LAN91C96_MSK_ERCV_INT     (0x1U << 6)
+#define LAN91C96_MSK_TX_IDLE_INT  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	Bank 3 Register Map in I/O Space
+ **************************************************************************
+ */
+#define LAN91C96_MGMT_MDO         (0x1U << 0)
+#define LAN91C96_MGMT_MDI         (0x1U << 1)
+#define LAN91C96_MGMT_MCLK        (0x1U << 2)
+#define LAN91C96_MGMT_MDOE        (0x1U << 3)
+#define LAN91C96_MGMT_LOW_ID      (0x3U << 4)
+#define LAN91C96_MGMT_IOS0        (0x1U << 8)
+#define LAN91C96_MGMT_IOS1        (0x1U << 9)
+#define LAN91C96_MGMT_IOS2        (0x1U << 10)
+#define LAN91C96_MGMT_nXNDEC      (0x1U << 11)
+#define LAN91C96_MGMT_HIGH_ID     (0x3U << 12)
+
+/*
+ ****************************************************************************
+ *	Revision Register - Bank 3 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_REV_REVID        (0xFU << 0)
+#define LAN91C96_REV_CHIPID       (0xFU << 4)
+
+/*
+ ****************************************************************************
+ *	Early RCV Register - Bank 3 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ERCV_THRESHOLD   (0x1FU << 0)
+#define LAN91C96_ERCV_RCV_DISCRD  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	PCMCIA Configuration Registers
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR    0x8000        /* Ethernet Configuration Register */
+#define LAN91C96_ECSR    0x8002        /* Ethernet Configuration and Status */
+
+/*
+ ****************************************************************************
+ *	PCMCIA Ethernet Configuration Option Register (ECOR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR_ENABLE       (0x1U << 0)
+#define LAN91C96_ECOR_WR_ATTRIB    (0x1U << 2)
+#define LAN91C96_ECOR_LEVEL_REQ    (0x1U << 6)
+#define LAN91C96_ECOR_SRESET       (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	PCMCIA Ethernet Configuration and Status Register (ECSR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECSR_INTR        (0x1U << 1)
+#define LAN91C96_ECSR_PWRDWN      (0x1U << 2)
+#define LAN91C96_ECSR_IOIS8       (0x1U << 5)
+
+/*
+ ****************************************************************************
+ *	Receive Frame Status Word - See page 38 of the LAN91C96 specification.
+ ****************************************************************************
+ */
+#define LAN91C96_TOO_SHORT        (0x1U << 10)
+#define LAN91C96_TOO_LONG         (0x1U << 11)
+#define LAN91C96_ODD_FRM          (0x1U << 12)
+#define LAN91C96_BAD_CRC          (0x1U << 13)
+#define LAN91C96_BROD_CAST        (0x1U << 14)
+#define LAN91C96_ALGN_ERR         (0x1U << 15)
+
+#define FRAME_FILTER              (LAN91C96_TOO_SHORT | LAN91C96_TOO_LONG  | LAN91C96_BAD_CRC   | LAN91C96_ALGN_ERR)
+
+/*
+ ****************************************************************************
+ *	Default MAC Address
+ ****************************************************************************
+ */
+#define MAC_DEF_HI  0x0800
+#define MAC_DEF_MED 0x3333
+#define MAC_DEF_LO  0x0100
+
+/*
+ ****************************************************************************
+ *	Default I/O Signature - 0x33
+ ****************************************************************************
+ */
+#define LAN91C96_LOW_SIGNATURE        (0x33U << 0)
+#define LAN91C96_HIGH_SIGNATURE       (0x33U << 8)
+#define LAN91C96_SIGNATURE (LAN91C96_HIGH_SIGNATURE | LAN91C96_LOW_SIGNATURE)
+
+#define LAN91C96_MAX_PAGES     6        /* Maximum number of 256 pages. */
+#define ETHERNET_MAX_LENGTH 1514
+
+
+/*-------------------------------------------------------------------------
+ *  I define some macros to make it easier to do somewhat common
+ * or slightly complicated, repeated tasks.
+ *-------------------------------------------------------------------------
+ */
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x)  { SMC_outw( x, LAN91C96_BANK_SELECT ); }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( LAN91C96_INT_MASK );\
+		mask |= (x);\
+		SMC_outb( mask, LAN91C96_INT_MASK ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( LAN91C96_INT_MASK );\
+		mask &= ~(x);\
+		SMC_outb( mask, LAN91C96_INT_MASK ); \
+}
+
+/*----------------------------------------------------------------------
+ * Define the interrupts that I want to receive from the card
+ *
+ * I want:
+ *  LAN91C96_IST_EPH_INT, for nasty errors
+ *  LAN91C96_IST_RCV_INT, for happy received packets
+ *  LAN91C96_IST_RX_OVRN_INT, because I have to kick the receiver
+ *-------------------------------------------------------------------------
+ */
+#define SMC_INTERRUPT_MASK   (LAN91C96_IST_EPH_INT | LAN91C96_IST_RX_OVRN_INT | LAN91C96_IST_RCV_INT)
+
+#endif  /* _LAN91C96_H_ */
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
new file mode 100644
index 0000000..95cdc49
--- /dev/null
+++ b/drivers/net/macb.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <common.h>
+
+#if defined(CONFIG_MACB) \
+	&& (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII))
+
+/*
+ * The u-boot networking stack is a little weird.  It seems like the
+ * networking core allocates receive buffers up front without any
+ * regard to the hardware that's supposed to actually receive those
+ * packets.
+ *
+ * The MACB receives packets into 128-byte receive buffers, so the
+ * buffers allocated by the core isn't very practical to use.  We'll
+ * allocate our own, but we need one such buffer in case a packet
+ * wraps around the DMA ring so that we have to copy it.
+ *
+ * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific
+ * configuration header.  This way, the core allocates one RX buffer
+ * and one TX buffer, each of which can hold a ethernet packet of
+ * maximum size.
+ *
+ * For some reason, the networking core unconditionally specifies a
+ * 32-byte packet "alignment" (which really should be called
+ * "padding").  MACB shouldn't need that, but we'll refrain from any
+ * core modifications here...
+ */
+
+#include <net.h>
+#include <malloc.h>
+
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/clk.h>
+
+#include "macb.h"
+
+#define barrier() asm volatile("" ::: "memory")
+
+#define CFG_MACB_RX_BUFFER_SIZE		4096
+#define CFG_MACB_RX_RING_SIZE		(CFG_MACB_RX_BUFFER_SIZE / 128)
+#define CFG_MACB_TX_RING_SIZE		16
+#define CFG_MACB_TX_TIMEOUT		1000
+#define CFG_MACB_AUTONEG_TIMEOUT	5000000
+
+struct macb_dma_desc {
+	u32	addr;
+	u32	ctrl;
+};
+
+#define RXADDR_USED		0x00000001
+#define RXADDR_WRAP		0x00000002
+
+#define RXBUF_FRMLEN_MASK	0x00000fff
+#define RXBUF_FRAME_START	0x00004000
+#define RXBUF_FRAME_END		0x00008000
+#define RXBUF_TYPEID_MATCH	0x00400000
+#define RXBUF_ADDR4_MATCH	0x00800000
+#define RXBUF_ADDR3_MATCH	0x01000000
+#define RXBUF_ADDR2_MATCH	0x02000000
+#define RXBUF_ADDR1_MATCH	0x04000000
+#define RXBUF_BROADCAST		0x80000000
+
+#define TXBUF_FRMLEN_MASK	0x000007ff
+#define TXBUF_FRAME_END		0x00008000
+#define TXBUF_NOCRC		0x00010000
+#define TXBUF_EXHAUSTED		0x08000000
+#define TXBUF_UNDERRUN		0x10000000
+#define TXBUF_MAXRETRY		0x20000000
+#define TXBUF_WRAP		0x40000000
+#define TXBUF_USED		0x80000000
+
+struct macb_device {
+	void			*regs;
+
+	unsigned int		rx_tail;
+	unsigned int		tx_head;
+	unsigned int		tx_tail;
+
+	void			*rx_buffer;
+	void			*tx_buffer;
+	struct macb_dma_desc	*rx_ring;
+	struct macb_dma_desc	*tx_ring;
+
+	unsigned long		rx_buffer_dma;
+	unsigned long		rx_ring_dma;
+	unsigned long		tx_ring_dma;
+
+	const struct device	*dev;
+	struct eth_device	netdev;
+	unsigned short		phy_addr;
+};
+#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
+
+static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+{
+	unsigned long netctl;
+	unsigned long netstat;
+	unsigned long frame;
+
+	netctl = macb_readl(macb, NCR);
+	netctl |= MACB_BIT(MPE);
+	macb_writel(macb, NCR, netctl);
+
+	frame = (MACB_BF(SOF, 1)
+		 | MACB_BF(RW, 1)
+		 | MACB_BF(PHYA, macb->phy_addr)
+		 | MACB_BF(REGA, reg)
+		 | MACB_BF(CODE, 2)
+		 | MACB_BF(DATA, value));
+	macb_writel(macb, MAN, frame);
+
+	do {
+		netstat = macb_readl(macb, NSR);
+	} while (!(netstat & MACB_BIT(IDLE)));
+
+	netctl = macb_readl(macb, NCR);
+	netctl &= ~MACB_BIT(MPE);
+	macb_writel(macb, NCR, netctl);
+}
+
+static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+{
+	unsigned long netctl;
+	unsigned long netstat;
+	unsigned long frame;
+
+	netctl = macb_readl(macb, NCR);
+	netctl |= MACB_BIT(MPE);
+	macb_writel(macb, NCR, netctl);
+
+	frame = (MACB_BF(SOF, 1)
+		 | MACB_BF(RW, 2)
+		 | MACB_BF(PHYA, macb->phy_addr)
+		 | MACB_BF(REGA, reg)
+		 | MACB_BF(CODE, 2));
+	macb_writel(macb, MAN, frame);
+
+	do {
+		netstat = macb_readl(macb, NSR);
+	} while (!(netstat & MACB_BIT(IDLE)));
+
+	frame = macb_readl(macb, MAN);
+
+	netctl = macb_readl(macb, NCR);
+	netctl &= ~MACB_BIT(MPE);
+	macb_writel(macb, NCR, netctl);
+
+	return MACB_BFEXT(DATA, frame);
+}
+
+#if defined(CONFIG_CMD_NET)
+
+static int macb_send(struct eth_device *netdev, volatile void *packet,
+		     int length)
+{
+	struct macb_device *macb = to_macb(netdev);
+	unsigned long paddr, ctrl;
+	unsigned int tx_head = macb->tx_head;
+	int i;
+
+	paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
+
+	ctrl = length & TXBUF_FRMLEN_MASK;
+	ctrl |= TXBUF_FRAME_END;
+	if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) {
+		ctrl |= TXBUF_WRAP;
+		macb->tx_head = 0;
+	} else
+		macb->tx_head++;
+
+	macb->tx_ring[tx_head].ctrl = ctrl;
+	macb->tx_ring[tx_head].addr = paddr;
+	barrier();
+	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
+
+	/*
+	 * I guess this is necessary because the networking core may
+	 * re-use the transmit buffer as soon as we return...
+	 */
+	for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
+		barrier();
+		ctrl = macb->tx_ring[tx_head].ctrl;
+		if (ctrl & TXBUF_USED)
+			break;
+		udelay(1);
+	}
+
+	dma_unmap_single(packet, length, paddr);
+
+	if (i <= CFG_MACB_TX_TIMEOUT) {
+		if (ctrl & TXBUF_UNDERRUN)
+			printf("%s: TX underrun\n", netdev->name);
+		if (ctrl & TXBUF_EXHAUSTED)
+			printf("%s: TX buffers exhausted in mid frame\n",
+			       netdev->name);
+	} else {
+		printf("%s: TX timeout\n", netdev->name);
+	}
+
+	/* No one cares anyway */
+	return 0;
+}
+
+static void reclaim_rx_buffers(struct macb_device *macb,
+			       unsigned int new_tail)
+{
+	unsigned int i;
+
+	i = macb->rx_tail;
+	while (i > new_tail) {
+		macb->rx_ring[i].addr &= ~RXADDR_USED;
+		i++;
+		if (i > CFG_MACB_RX_RING_SIZE)
+			i = 0;
+	}
+
+	while (i < new_tail) {
+		macb->rx_ring[i].addr &= ~RXADDR_USED;
+		i++;
+	}
+
+	barrier();
+	macb->rx_tail = new_tail;
+}
+
+static int macb_recv(struct eth_device *netdev)
+{
+	struct macb_device *macb = to_macb(netdev);
+	unsigned int rx_tail = macb->rx_tail;
+	void *buffer;
+	int length;
+	int wrapped = 0;
+	u32 status;
+
+	for (;;) {
+		if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
+			return -1;
+
+		status = macb->rx_ring[rx_tail].ctrl;
+		if (status & RXBUF_FRAME_START) {
+			if (rx_tail != macb->rx_tail)
+				reclaim_rx_buffers(macb, rx_tail);
+			wrapped = 0;
+		}
+
+		if (status & RXBUF_FRAME_END) {
+			buffer = macb->rx_buffer + 128 * macb->rx_tail;
+			length = status & RXBUF_FRMLEN_MASK;
+			if (wrapped) {
+				unsigned int headlen, taillen;
+
+				headlen = 128 * (CFG_MACB_RX_RING_SIZE
+						 - macb->rx_tail);
+				taillen = length - headlen;
+				memcpy((void *)NetRxPackets[0],
+				       buffer, headlen);
+				memcpy((void *)NetRxPackets[0] + headlen,
+				       macb->rx_buffer, taillen);
+				buffer = (void *)NetRxPackets[0];
+			}
+
+			NetReceive(buffer, length);
+			if (++rx_tail >= CFG_MACB_RX_RING_SIZE)
+				rx_tail = 0;
+			reclaim_rx_buffers(macb, rx_tail);
+		} else {
+			if (++rx_tail >= CFG_MACB_RX_RING_SIZE) {
+				wrapped = 1;
+				rx_tail = 0;
+			}
+		}
+		barrier();
+	}
+
+	return 0;
+}
+
+static void macb_phy_reset(struct macb_device *macb)
+{
+	struct eth_device *netdev = &macb->netdev;
+	int i;
+	u16 status, adv;
+
+	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+	macb_mdio_write(macb, MII_ADVERTISE, adv);
+	printf("%s: Starting autonegotiation...\n", netdev->name);
+	macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+					 | BMCR_ANRESTART));
+
+	for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+		status = macb_mdio_read(macb, MII_BMSR);
+		if (status & BMSR_ANEGCOMPLETE)
+			break;
+		udelay(100);
+	}
+
+	if (status & BMSR_ANEGCOMPLETE)
+		printf("%s: Autonegotiation complete\n", netdev->name);
+	else
+		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+		       netdev->name, status);
+}
+
+static int macb_phy_init(struct macb_device *macb)
+{
+	struct eth_device *netdev = &macb->netdev;
+	u32 ncfgr;
+	u16 phy_id, status, adv, lpa;
+	int media, speed, duplex;
+	int i;
+
+	/* Check if the PHY is up to snuff... */
+	phy_id = macb_mdio_read(macb, MII_PHYSID1);
+	if (phy_id == 0xffff) {
+		printf("%s: No PHY present\n", netdev->name);
+		return 0;
+	}
+
+	status = macb_mdio_read(macb, MII_BMSR);
+	if (!(status & BMSR_LSTATUS)) {
+		/* Try to re-negotiate if we don't have link already. */
+		macb_phy_reset(macb);
+
+		for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+			status = macb_mdio_read(macb, MII_BMSR);
+			if (status & BMSR_LSTATUS)
+				break;
+			udelay(100);
+		}
+	}
+
+	if (!(status & BMSR_LSTATUS)) {
+		printf("%s: link down (status: 0x%04x)\n",
+		       netdev->name, status);
+		return 0;
+	} else {
+		adv = macb_mdio_read(macb, MII_ADVERTISE);
+		lpa = macb_mdio_read(macb, MII_LPA);
+		media = mii_nway_result(lpa & adv);
+		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+			 ? 1 : 0);
+		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+		printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+		       netdev->name,
+		       speed ? "100" : "10",
+		       duplex ? "full" : "half",
+		       lpa);
+
+		ncfgr = macb_readl(macb, NCFGR);
+		ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+		if (speed)
+			ncfgr |= MACB_BIT(SPD);
+		if (duplex)
+			ncfgr |= MACB_BIT(FD);
+		macb_writel(macb, NCFGR, ncfgr);
+		return 1;
+	}
+}
+
+static int macb_init(struct eth_device *netdev, bd_t *bd)
+{
+	struct macb_device *macb = to_macb(netdev);
+	unsigned long paddr;
+	u32 hwaddr_bottom;
+	u16 hwaddr_top;
+	int i;
+
+	/*
+	 * macb_halt should have been called at some point before now,
+	 * so we'll assume the controller is idle.
+	 */
+
+	/* initialize DMA descriptors */
+	paddr = macb->rx_buffer_dma;
+	for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) {
+		if (i == (CFG_MACB_RX_RING_SIZE - 1))
+			paddr |= RXADDR_WRAP;
+		macb->rx_ring[i].addr = paddr;
+		macb->rx_ring[i].ctrl = 0;
+		paddr += 128;
+	}
+	for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) {
+		macb->tx_ring[i].addr = 0;
+		if (i == (CFG_MACB_TX_RING_SIZE - 1))
+			macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+		else
+			macb->tx_ring[i].ctrl = TXBUF_USED;
+	}
+	macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
+
+	macb_writel(macb, RBQP, macb->rx_ring_dma);
+	macb_writel(macb, TBQP, macb->tx_ring_dma);
+
+	/* set hardware address */
+	hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr));
+	macb_writel(macb, SA1B, hwaddr_bottom);
+	hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4)));
+	macb_writel(macb, SA1T, hwaddr_top);
+
+	/* choose RMII or MII mode. This depends on the board */
+#ifdef CONFIG_RMII
+	macb_writel(macb, USRIO, 0);
+#else
+	macb_writel(macb, USRIO, MACB_BIT(MII));
+#endif
+
+	if (!macb_phy_init(macb))
+		return 0;
+
+	/* Enable TX and RX */
+	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
+
+	return 1;
+}
+
+static void macb_halt(struct eth_device *netdev)
+{
+	struct macb_device *macb = to_macb(netdev);
+	u32 ncr, tsr;
+
+	/* Halt the controller and wait for any ongoing transmission to end. */
+	ncr = macb_readl(macb, NCR);
+	ncr |= MACB_BIT(THALT);
+	macb_writel(macb, NCR, ncr);
+
+	do {
+		tsr = macb_readl(macb, TSR);
+	} while (tsr & MACB_BIT(TGO));
+
+	/* Disable TX and RX, and clear statistics */
+	macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
+}
+
+int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
+{
+	struct macb_device *macb;
+	struct eth_device *netdev;
+	unsigned long macb_hz;
+	u32 ncfgr;
+
+	macb = malloc(sizeof(struct macb_device));
+	if (!macb) {
+		printf("Error: Failed to allocate memory for MACB%d\n", id);
+		return -1;
+	}
+	memset(macb, 0, sizeof(struct macb_device));
+
+	netdev = &macb->netdev;
+
+	macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE,
+					     &macb->rx_buffer_dma);
+	macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE
+					   * sizeof(struct macb_dma_desc),
+					   &macb->rx_ring_dma);
+	macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE
+					   * sizeof(struct macb_dma_desc),
+					   &macb->tx_ring_dma);
+
+	macb->regs = regs;
+	macb->phy_addr = phy_addr;
+
+	sprintf(netdev->name, "macb%d", id);
+	netdev->init = macb_init;
+	netdev->halt = macb_halt;
+	netdev->send = macb_send;
+	netdev->recv = macb_recv;
+
+	/*
+	 * Do some basic initialization so that we at least can talk
+	 * to the PHY
+	 */
+	macb_hz = get_macb_pclk_rate(id);
+	if (macb_hz < 20000000)
+		ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
+	else if (macb_hz < 40000000)
+		ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
+	else if (macb_hz < 80000000)
+		ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
+	else
+		ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
+
+	macb_writel(macb, NCFGR, ncfgr);
+
+	eth_register(netdev);
+
+	return 0;
+}
+
+#endif
+
+#if defined(CONFIG_CMD_MII)
+
+int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
+{
+	unsigned long netctl;
+	unsigned long netstat;
+	unsigned long frame;
+	int iflag;
+
+	iflag = disable_interrupts();
+	netctl = macb_readl(&macb, EMACB_NCR);
+	netctl |= MACB_BIT(MPE);
+	macb_writel(&macb, EMACB_NCR, netctl);
+	if (iflag)
+		enable_interrupts();
+
+	frame = (MACB_BF(SOF, 1)
+		 | MACB_BF(RW, 2)
+		 | MACB_BF(PHYA, addr)
+		 | MACB_BF(REGA, reg)
+		 | MACB_BF(CODE, 2));
+	macb_writel(&macb, EMACB_MAN, frame);
+
+	do {
+		netstat = macb_readl(&macb, EMACB_NSR);
+	} while (!(netstat & MACB_BIT(IDLE)));
+
+	frame = macb_readl(&macb, EMACB_MAN);
+	*value = MACB_BFEXT(DATA, frame);
+
+	iflag = disable_interrupts();
+	netctl = macb_readl(&macb, EMACB_NCR);
+	netctl &= ~MACB_BIT(MPE);
+	macb_writel(&macb, EMACB_NCR, netctl);
+	if (iflag)
+		enable_interrupts();
+
+	return 0;
+}
+
+int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
+{
+	unsigned long netctl;
+	unsigned long netstat;
+	unsigned long frame;
+	int iflag;
+
+	iflag = disable_interrupts();
+	netctl = macb_readl(&macb, EMACB_NCR);
+	netctl |= MACB_BIT(MPE);
+	macb_writel(&macb, EMACB_NCR, netctl);
+	if (iflag)
+		enable_interrupts();
+
+	frame = (MACB_BF(SOF, 1)
+		 | MACB_BF(RW, 1)
+		 | MACB_BF(PHYA, addr)
+		 | MACB_BF(REGA, reg)
+		 | MACB_BF(CODE, 2)
+		 | MACB_BF(DATA, value));
+	macb_writel(&macb, EMACB_MAN, frame);
+
+	do {
+		netstat = macb_readl(&macb, EMACB_NSR);
+	} while (!(netstat & MACB_BIT(IDLE)));
+
+	iflag = disable_interrupts();
+	netctl = macb_readl(&macb, EMACB_NCR);
+	netctl &= ~MACB_BIT(MPE);
+	macb_writel(&macb, EMACB_NCR, netctl);
+	if (iflag)
+		enable_interrupts();
+
+	return 0;
+}
+
+#endif
+
+#endif /* CONFIG_MACB */
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
new file mode 100644
index 0000000..c778e4e
--- /dev/null
+++ b/drivers/net/macb.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __DRIVERS_MACB_H__
+#define __DRIVERS_MACB_H__
+
+/* MACB register offsets */
+#define MACB_NCR				0x0000
+#define MACB_NCFGR				0x0004
+#define MACB_NSR				0x0008
+#define MACB_TSR				0x0014
+#define MACB_RBQP				0x0018
+#define MACB_TBQP				0x001c
+#define MACB_RSR				0x0020
+#define MACB_ISR				0x0024
+#define MACB_IER				0x0028
+#define MACB_IDR				0x002c
+#define MACB_IMR				0x0030
+#define MACB_MAN				0x0034
+#define MACB_PTR				0x0038
+#define MACB_PFR				0x003c
+#define MACB_FTO				0x0040
+#define MACB_SCF				0x0044
+#define MACB_MCF				0x0048
+#define MACB_FRO				0x004c
+#define MACB_FCSE				0x0050
+#define MACB_ALE				0x0054
+#define MACB_DTF				0x0058
+#define MACB_LCOL				0x005c
+#define MACB_EXCOL				0x0060
+#define MACB_TUND				0x0064
+#define MACB_CSE				0x0068
+#define MACB_RRE				0x006c
+#define MACB_ROVR				0x0070
+#define MACB_RSE				0x0074
+#define MACB_ELE				0x0078
+#define MACB_RJA				0x007c
+#define MACB_USF				0x0080
+#define MACB_STE				0x0084
+#define MACB_RLE				0x0088
+#define MACB_TPF				0x008c
+#define MACB_HRB				0x0090
+#define MACB_HRT				0x0094
+#define MACB_SA1B				0x0098
+#define MACB_SA1T				0x009c
+#define MACB_SA2B				0x00a0
+#define MACB_SA2T				0x00a4
+#define MACB_SA3B				0x00a8
+#define MACB_SA3T				0x00ac
+#define MACB_SA4B				0x00b0
+#define MACB_SA4T				0x00b4
+#define MACB_TID				0x00b8
+#define MACB_TPQ				0x00bc
+#define MACB_USRIO				0x00c0
+#define MACB_WOL				0x00c4
+
+/* Bitfields in NCR */
+#define MACB_LB_OFFSET				0
+#define MACB_LB_SIZE				1
+#define MACB_LLB_OFFSET				1
+#define MACB_LLB_SIZE				1
+#define MACB_RE_OFFSET				2
+#define MACB_RE_SIZE				1
+#define MACB_TE_OFFSET				3
+#define MACB_TE_SIZE				1
+#define MACB_MPE_OFFSET				4
+#define MACB_MPE_SIZE				1
+#define MACB_CLRSTAT_OFFSET			5
+#define MACB_CLRSTAT_SIZE			1
+#define MACB_INCSTAT_OFFSET			6
+#define MACB_INCSTAT_SIZE			1
+#define MACB_WESTAT_OFFSET			7
+#define MACB_WESTAT_SIZE			1
+#define MACB_BP_OFFSET				8
+#define MACB_BP_SIZE				1
+#define MACB_TSTART_OFFSET			9
+#define MACB_TSTART_SIZE			1
+#define MACB_THALT_OFFSET			10
+#define MACB_THALT_SIZE				1
+#define MACB_NCR_TPF_OFFSET			11
+#define MACB_NCR_TPF_SIZE			1
+#define MACB_TZQ_OFFSET				12
+#define MACB_TZQ_SIZE				1
+
+/* Bitfields in NCFGR */
+#define MACB_SPD_OFFSET				0
+#define MACB_SPD_SIZE				1
+#define MACB_FD_OFFSET				1
+#define MACB_FD_SIZE				1
+#define MACB_BIT_RATE_OFFSET			2
+#define MACB_BIT_RATE_SIZE			1
+#define MACB_JFRAME_OFFSET			3
+#define MACB_JFRAME_SIZE			1
+#define MACB_CAF_OFFSET				4
+#define MACB_CAF_SIZE				1
+#define MACB_NBC_OFFSET				5
+#define MACB_NBC_SIZE				1
+#define MACB_NCFGR_MTI_OFFSET			6
+#define MACB_NCFGR_MTI_SIZE			1
+#define MACB_UNI_OFFSET				7
+#define MACB_UNI_SIZE				1
+#define MACB_BIG_OFFSET				8
+#define MACB_BIG_SIZE				1
+#define MACB_EAE_OFFSET				9
+#define MACB_EAE_SIZE				1
+#define MACB_CLK_OFFSET				10
+#define MACB_CLK_SIZE				2
+#define MACB_RTY_OFFSET				12
+#define MACB_RTY_SIZE				1
+#define MACB_PAE_OFFSET				13
+#define MACB_PAE_SIZE				1
+#define MACB_RBOF_OFFSET			14
+#define MACB_RBOF_SIZE				2
+#define MACB_RLCE_OFFSET			16
+#define MACB_RLCE_SIZE				1
+#define MACB_DRFCS_OFFSET			17
+#define MACB_DRFCS_SIZE				1
+#define MACB_EFRHD_OFFSET			18
+#define MACB_EFRHD_SIZE				1
+#define MACB_IRXFCS_OFFSET			19
+#define MACB_IRXFCS_SIZE			1
+
+/* Bitfields in NSR */
+#define MACB_NSR_LINK_OFFSET			0
+#define MACB_NSR_LINK_SIZE			1
+#define MACB_MDIO_OFFSET			1
+#define MACB_MDIO_SIZE				1
+#define MACB_IDLE_OFFSET			2
+#define MACB_IDLE_SIZE				1
+
+/* Bitfields in TSR */
+#define MACB_UBR_OFFSET				0
+#define MACB_UBR_SIZE				1
+#define MACB_COL_OFFSET				1
+#define MACB_COL_SIZE				1
+#define MACB_TSR_RLE_OFFSET			2
+#define MACB_TSR_RLE_SIZE			1
+#define MACB_TGO_OFFSET				3
+#define MACB_TGO_SIZE				1
+#define MACB_BEX_OFFSET				4
+#define MACB_BEX_SIZE				1
+#define MACB_COMP_OFFSET			5
+#define MACB_COMP_SIZE				1
+#define MACB_UND_OFFSET				6
+#define MACB_UND_SIZE				1
+
+/* Bitfields in RSR */
+#define MACB_BNA_OFFSET				0
+#define MACB_BNA_SIZE				1
+#define MACB_REC_OFFSET				1
+#define MACB_REC_SIZE				1
+#define MACB_OVR_OFFSET				2
+#define MACB_OVR_SIZE				1
+
+/* Bitfields in ISR/IER/IDR/IMR */
+#define MACB_MFD_OFFSET				0
+#define MACB_MFD_SIZE				1
+#define MACB_RCOMP_OFFSET			1
+#define MACB_RCOMP_SIZE				1
+#define MACB_RXUBR_OFFSET			2
+#define MACB_RXUBR_SIZE				1
+#define MACB_TXUBR_OFFSET			3
+#define MACB_TXUBR_SIZE				1
+#define MACB_ISR_TUND_OFFSET			4
+#define MACB_ISR_TUND_SIZE			1
+#define MACB_ISR_RLE_OFFSET			5
+#define MACB_ISR_RLE_SIZE			1
+#define MACB_TXERR_OFFSET			6
+#define MACB_TXERR_SIZE				1
+#define MACB_TCOMP_OFFSET			7
+#define MACB_TCOMP_SIZE				1
+#define MACB_ISR_LINK_OFFSET			9
+#define MACB_ISR_LINK_SIZE			1
+#define MACB_ISR_ROVR_OFFSET			10
+#define MACB_ISR_ROVR_SIZE			1
+#define MACB_HRESP_OFFSET			11
+#define MACB_HRESP_SIZE				1
+#define MACB_PFR_OFFSET				12
+#define MACB_PFR_SIZE				1
+#define MACB_PTZ_OFFSET				13
+#define MACB_PTZ_SIZE				1
+
+/* Bitfields in MAN */
+#define MACB_DATA_OFFSET			0
+#define MACB_DATA_SIZE				16
+#define MACB_CODE_OFFSET			16
+#define MACB_CODE_SIZE				2
+#define MACB_REGA_OFFSET			18
+#define MACB_REGA_SIZE				5
+#define MACB_PHYA_OFFSET			23
+#define MACB_PHYA_SIZE				5
+#define MACB_RW_OFFSET				28
+#define MACB_RW_SIZE				2
+#define MACB_SOF_OFFSET				30
+#define MACB_SOF_SIZE				2
+
+/* Bitfields in USRIO */
+#define MACB_MII_OFFSET				0
+#define MACB_MII_SIZE				1
+#define MACB_EAM_OFFSET				1
+#define MACB_EAM_SIZE				1
+#define MACB_TX_PAUSE_OFFSET			2
+#define MACB_TX_PAUSE_SIZE			1
+#define MACB_TX_PAUSE_ZERO_OFFSET		3
+#define MACB_TX_PAUSE_ZERO_SIZE			1
+
+/* Bitfields in WOL */
+#define MACB_IP_OFFSET				0
+#define MACB_IP_SIZE				16
+#define MACB_MAG_OFFSET				16
+#define MACB_MAG_SIZE				1
+#define MACB_ARP_OFFSET				17
+#define MACB_ARP_SIZE				1
+#define MACB_SA1_OFFSET				18
+#define MACB_SA1_SIZE				1
+#define MACB_WOL_MTI_OFFSET			19
+#define MACB_WOL_MTI_SIZE			1
+
+/* Constants for CLK */
+#define MACB_CLK_DIV8				0
+#define MACB_CLK_DIV16				1
+#define MACB_CLK_DIV32				2
+#define MACB_CLK_DIV64				3
+
+/* Constants for MAN register */
+#define MACB_MAN_SOF				1
+#define MACB_MAN_WRITE				1
+#define MACB_MAN_READ				2
+#define MACB_MAN_CODE				2
+
+/* Bit manipulation macros */
+#define MACB_BIT(name)					\
+	(1 << MACB_##name##_OFFSET)
+#define MACB_BF(name,value)				\
+	(((value) & ((1 << MACB_##name##_SIZE) - 1))	\
+	 << MACB_##name##_OFFSET)
+#define MACB_BFEXT(name,value)\
+	(((value) >> MACB_##name##_OFFSET)		\
+	 & ((1 << MACB_##name##_SIZE) - 1))
+#define MACB_BFINS(name,value,old)			\
+	(((old) & ~(((1 << MACB_##name##_SIZE) - 1)	\
+		    << MACB_##name##_OFFSET))		\
+	 | MACB_BF(name,value))
+
+/* Register access macros */
+#define macb_readl(port,reg)				\
+	readl((port)->regs + MACB_##reg)
+#define macb_writel(port,reg,value)			\
+	writel((value), (port)->regs + MACB_##reg)
+
+#endif /* __DRIVERS_MACB_H__ */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
new file mode 100644
index 0000000..075d6c5
--- /dev/null
+++ b/drivers/net/natsemi.c
@@ -0,0 +1,882 @@
+/*
+   natsemi.c: A U-Boot driver for the NatSemi DP8381x series.
+   Author: Mark A. Rakes (mark_rakes@vivato.net)
+
+   Adapted from an Etherboot driver written by:
+
+   Copyright (C) 2001 Entity Cyber, Inc.
+
+   This development of this Etherboot driver was funded by
+
+      Sicom Systems: http://www.sicompos.com/
+
+   Author: Marty Connor (mdc@thinguin.org)
+   Adapted from a Linux driver which was written by Donald Becker
+
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+
+   Original Copyright Notice:
+
+   Written/copyright 1999-2001 by Donald Becker.
+
+   This software may be used and distributed according to the terms of
+   the GNU General Public License (GPL), incorporated herein by reference.
+   Drivers based on or derived from this code fall under the GPL and must
+   retain the authorship, copyright and license notice.  This file is not
+   a complete program and may only be used when the entire operating
+   system is licensed under the GPL.  License for under other terms may be
+   available.  Contact the original author for details.
+
+   The original author may be reached as becker@scyld.com, or at
+   Scyld Computing Corporation
+   410 Severn Ave., Suite 210
+   Annapolis MD 21403
+
+   Support information and updates available at
+   http://www.scyld.com/network/netsemi.html
+
+   References:
+   http://www.scyld.com/expert/100mbps.html
+   http://www.scyld.com/expert/NWay.html
+   Datasheet is available from:
+   http://www.national.com/pf/DP/DP83815.html
+*/
+
+/* Revision History
+ * October 2002 mar	1.0
+ *   Initial U-Boot Release.  Tested with Netgear FA311 board
+ *   and dp83815 chipset on custom board
+*/
+
+/* Includes */
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_NATSEMI)
+
+/* defines */
+#define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/
+
+#define DSIZE     0x00000FFF
+#define ETH_ALEN	6
+#define CRC_SIZE  4
+#define TOUT_LOOP   500000
+#define TX_BUF_SIZE    1536
+#define RX_BUF_SIZE    1536
+#define NUM_RX_DESC    4	/* Number of Rx descriptor registers. */
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  */
+enum register_offsets {
+	ChipCmd 	= 0x00,
+	ChipConfig 	= 0x04,
+	EECtrl 		= 0x08,
+	IntrMask 	= 0x14,
+	IntrEnable 	= 0x18,
+	TxRingPtr 	= 0x20,
+	TxConfig 	= 0x24,
+	RxRingPtr 	= 0x30,
+	RxConfig 	= 0x34,
+	ClkRun 		= 0x3C,
+	RxFilterAddr 	= 0x48,
+	RxFilterData 	= 0x4C,
+	SiliconRev 	= 0x58,
+	PCIPM 		= 0x44,
+	BasicControl	= 0x80,
+	BasicStatus	= 0x84,
+	/* These are from the spec, around page 78... on a separate table. */
+	PGSEL 		= 0xCC,
+	PMDCSR 		= 0xE4,
+	TSTDAT 		= 0xFC,
+	DSPCFG 		= 0xF4,
+	SDCFG 		= 0x8C
+};
+
+/* Bit in ChipCmd. */
+enum ChipCmdBits {
+	ChipReset 	= 0x100,
+	RxReset 	= 0x20,
+	TxReset 	= 0x10,
+	RxOff 		= 0x08,
+	RxOn 		= 0x04,
+	TxOff 		= 0x02,
+	TxOn 		= 0x01
+};
+
+enum ChipConfigBits {
+	LinkSts 	= 0x80000000,
+	HundSpeed 	= 0x40000000,
+	FullDuplex 	= 0x20000000,
+	TenPolarity	= 0x10000000,
+	AnegDone	= 0x08000000,
+	AnegEnBothBoth	= 0x0000E000,
+	AnegDis100Full	= 0x0000C000,
+	AnegEn100Both	= 0x0000A000,
+	AnegDis100Half	= 0x00008000,
+	AnegEnBothHalf	= 0x00006000,
+	AnegDis10Full	= 0x00004000,
+	AnegEn10Both	= 0x00002000,
+	DuplexMask	= 0x00008000,
+	SpeedMask	= 0x00004000,
+	AnegMask	= 0x00002000,
+	AnegDis10Half	= 0x00000000,
+	ExtPhy 		= 0x00001000,
+	PhyRst 		= 0x00000400,
+	PhyDis 		= 0x00000200,
+	BootRomDisable	= 0x00000004,
+	BEMode 		= 0x00000001,
+};
+
+enum TxConfig_bits {
+	TxDrthMask 	= 0x3f,
+	TxFlthMask 	= 0x3f00,
+	TxMxdmaMask	= 0x700000,
+	TxMxdma_512 	= 0x0,
+	TxMxdma_4 	= 0x100000,
+	TxMxdma_8 	= 0x200000,
+	TxMxdma_16 	= 0x300000,
+	TxMxdma_32 	= 0x400000,
+	TxMxdma_64 	= 0x500000,
+	TxMxdma_128 	= 0x600000,
+	TxMxdma_256 	= 0x700000,
+	TxCollRetry 	= 0x800000,
+	TxAutoPad 	= 0x10000000,
+	TxMacLoop 	= 0x20000000,
+	TxHeartIgn 	= 0x40000000,
+	TxCarrierIgn 	= 0x80000000
+};
+
+enum RxConfig_bits {
+	RxDrthMask 	= 0x3e,
+	RxMxdmaMask 	= 0x700000,
+	RxMxdma_512 	= 0x0,
+	RxMxdma_4 	= 0x100000,
+	RxMxdma_8 	= 0x200000,
+	RxMxdma_16 	= 0x300000,
+	RxMxdma_32 	= 0x400000,
+	RxMxdma_64 	= 0x500000,
+	RxMxdma_128 	= 0x600000,
+	RxMxdma_256 	= 0x700000,
+	RxAcceptLong 	= 0x8000000,
+	RxAcceptTx 	= 0x10000000,
+	RxAcceptRunt 	= 0x40000000,
+	RxAcceptErr 	= 0x80000000
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+	AcceptErr 		= 0x20,
+	AcceptRunt 		= 0x10,
+	AcceptBroadcast 	= 0xC0000000,
+	AcceptMulticast 	= 0x00200000,
+	AcceptAllMulticast 	= 0x20000000,
+	AcceptAllPhys 		= 0x10000000,
+	AcceptMyPhys 		= 0x08000000
+};
+
+typedef struct _BufferDesc {
+	u32 link;
+	vu_long cmdsts;
+	u32 bufptr;
+	u32 software_use;
+} BufferDesc;
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+	DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000,
+	DescNoCRC = 0x10000000, DescPktOK = 0x08000000,
+	DescSizeMask = 0xfff,
+
+	DescTxAbort = 0x04000000, DescTxFIFO = 0x02000000,
+	DescTxCarrier = 0x01000000, DescTxDefer = 0x00800000,
+	DescTxExcDefer = 0x00400000, DescTxOOWCol = 0x00200000,
+	DescTxExcColl = 0x00100000, DescTxCollCount = 0x000f0000,
+
+	DescRxAbort = 0x04000000, DescRxOver = 0x02000000,
+	DescRxDest = 0x01800000, DescRxLong = 0x00400000,
+	DescRxRunt = 0x00200000, DescRxInvalid = 0x00100000,
+	DescRxCRC = 0x00080000, DescRxAlign = 0x00040000,
+	DescRxLoop = 0x00020000, DesRxColl = 0x00010000,
+};
+
+/* Globals */
+#ifdef NATSEMI_DEBUG
+static int natsemi_debug = 0;	/* 1 verbose debugging, 0 normal */
+#endif
+static u32 SavedClkRun;
+static unsigned int cur_rx;
+static unsigned int advertising;
+static unsigned int rx_config;
+static unsigned int tx_config;
+
+/* Note: transmit and receive buffers and descriptors must be
+   longword aligned */
+static BufferDesc txd __attribute__ ((aligned(4)));
+static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
+
+static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]
+    __attribute__ ((aligned(4)));
+
+/* Function Prototypes */
+#if 0
+static void write_eeprom(struct eth_device *dev, long addr, int location,
+			 short value);
+#endif
+static int read_eeprom(struct eth_device *dev, long addr, int location);
+static int mdio_read(struct eth_device *dev, int phy_id, int location);
+static int natsemi_init(struct eth_device *dev, bd_t * bis);
+static void natsemi_reset(struct eth_device *dev);
+static void natsemi_init_rxfilter(struct eth_device *dev);
+static void natsemi_init_txd(struct eth_device *dev);
+static void natsemi_init_rxd(struct eth_device *dev);
+static void natsemi_set_rx_mode(struct eth_device *dev);
+static void natsemi_check_duplex(struct eth_device *dev);
+static int natsemi_send(struct eth_device *dev, volatile void *packet,
+			int length);
+static int natsemi_poll(struct eth_device *dev);
+static void natsemi_disable(struct eth_device *dev);
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815},
+	{}
+};
+
+#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+static inline int
+INW(struct eth_device *dev, u_long addr)
+{
+	return le16_to_cpu(*(vu_short *) (addr + dev->iobase));
+}
+
+static int
+INL(struct eth_device *dev, u_long addr)
+{
+	return le32_to_cpu(*(vu_long *) (addr + dev->iobase));
+}
+
+static inline void
+OUTW(struct eth_device *dev, int command, u_long addr)
+{
+	*(vu_short *) ((addr + dev->iobase)) = cpu_to_le16(command);
+}
+
+static inline void
+OUTL(struct eth_device *dev, int command, u_long addr)
+{
+	*(vu_long *) ((addr + dev->iobase)) = cpu_to_le32(command);
+}
+
+/*
+ * Function: natsemi_initialize
+ *
+ * Description: Retrieves the MAC address of the card, and sets up some
+ * globals required by other routines,  and initializes the NIC, making it
+ * ready to send and receive packets.
+ *
+ * Side effects:
+ *            leaves the natsemi initialized, and ready to recieve packets.
+ *
+ * Returns:   struct eth_device *:          pointer to NIC data structure
+ */
+
+int
+natsemi_initialize(bd_t * bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	u32 iobase, status, chip_config;
+	int i, idx = 0;
+	int prev_eedata;
+	u32 tmp;
+
+	while (1) {
+		/* Find PCI device(s) */
+		if ((devno = pci_find_devices(supported, idx++)) < 0) {
+			break;
+		}
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
+		iobase &= ~0x3;	/* bit 1: unused and bit 0: I/O Space Indicator */
+
+		pci_write_config_dword(devno, PCI_COMMAND,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+		/* Check if I/O accesses and Bus Mastering are enabled. */
+		pci_read_config_dword(devno, PCI_COMMAND, &status);
+		if (!(status & PCI_COMMAND_MEMORY)) {
+			printf("Error: Can not enable MEM access.\n");
+			continue;
+		} else if (!(status & PCI_COMMAND_MASTER)) {
+			printf("Error: Can not enable Bus Mastering.\n");
+			continue;
+		}
+
+		dev = (struct eth_device *) malloc(sizeof *dev);
+
+		sprintf(dev->name, "dp83815#%d", card_number);
+		dev->iobase = bus_to_phys(iobase);
+#ifdef NATSEMI_DEBUG
+		printf("natsemi: NatSemi ns8381[56] @ %#x\n", dev->iobase);
+#endif
+		dev->priv = (void *) devno;
+		dev->init = natsemi_init;
+		dev->halt = natsemi_disable;
+		dev->send = natsemi_send;
+		dev->recv = natsemi_poll;
+
+		eth_register(dev);
+
+		card_number++;
+
+		/* Set the latency timer for value. */
+		pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
+
+		udelay(10 * 1000);
+
+		/* natsemi has a non-standard PM control register
+		 * in PCI config space.  Some boards apparently need
+		 * to be brought to D0 in this manner.  */
+		pci_read_config_dword(devno, PCIPM, &tmp);
+		if (tmp & (0x03 | 0x100)) {
+			/* D0 state, disable PME assertion */
+			u32 newtmp = tmp & ~(0x03 | 0x100);
+			pci_write_config_dword(devno, PCIPM, newtmp);
+		}
+
+		printf("natsemi: EEPROM contents:\n");
+		for (i = 0; i <= EEPROM_SIZE; i++) {
+			short eedata = read_eeprom(dev, EECtrl, i);
+			printf(" %04hx", eedata);
+		}
+		printf("\n");
+
+		/* get MAC address */
+		prev_eedata = read_eeprom(dev, EECtrl, 6);
+		for (i = 0; i < 3; i++) {
+			int eedata = read_eeprom(dev, EECtrl, i + 7);
+			dev->enetaddr[i*2] = (eedata << 1) + (prev_eedata >> 15);
+			dev->enetaddr[i*2+1] = eedata >> 7;
+			prev_eedata = eedata;
+		}
+
+		/* Reset the chip to erase any previous misconfiguration. */
+		OUTL(dev, ChipReset, ChipCmd);
+
+		advertising = mdio_read(dev, 1, 4);
+		chip_config = INL(dev, ChipConfig);
+#ifdef NATSEMI_DEBUG
+		printf("%s: Transceiver status %#08X advertising %#08X\n",
+		       	dev->name, (int) INL(dev, BasicStatus), advertising);
+		printf("%s: Transceiver default autoneg. %s 10%s %s duplex.\n",
+			dev->name, chip_config & AnegMask ? "enabled, advertise" :
+			"disabled, force", chip_config & SpeedMask ? "0" : "",
+			chip_config & DuplexMask ? "full" : "half");
+#endif
+		chip_config |= AnegEnBothBoth;
+#ifdef NATSEMI_DEBUG
+		printf("%s: changed to autoneg. %s 10%s %s duplex.\n",
+			dev->name, chip_config & AnegMask ? "enabled, advertise" :
+			"disabled, force", chip_config & SpeedMask ? "0" : "",
+			chip_config & DuplexMask ? "full" : "half");
+#endif
+		/*write new autoneg bits, reset phy*/
+		OUTL(dev, (chip_config | PhyRst), ChipConfig);
+		/*un-reset phy*/
+		OUTL(dev, chip_config, ChipConfig);
+
+		/* Disable PME:
+		 * The PME bit is initialized from the EEPROM contents.
+		 * PCI cards probably have PME disabled, but motherboard
+		 * implementations may have PME set to enable WakeOnLan.
+		 * With PME set the chip will scan incoming packets but
+		 * nothing will be written to memory. */
+		SavedClkRun = INL(dev, ClkRun);
+		OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+	}
+	return card_number;
+}
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
+   The EEPROM code is for common 93c06/46 EEPROMs w/ 6bit addresses.  */
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but future 66Mhz
+   access may need a delay. */
+#define eeprom_delay(ee_addr)	INL(dev, ee_addr)
+
+enum EEPROM_Ctrl_Bits {
+	EE_ShiftClk = 0x04,
+	EE_DataIn = 0x01,
+	EE_ChipSelect = 0x08,
+	EE_DataOut = 0x02
+};
+
+#define EE_Write0 (EE_ChipSelect)
+#define EE_Write1 (EE_ChipSelect | EE_DataIn)
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+	EE_WrEnCmd = (4 << 6), EE_WriteCmd = (5 << 6),
+	EE_ReadCmd = (6 << 6), EE_EraseCmd = (7 << 6),
+};
+
+#if 0
+static void
+write_eeprom(struct eth_device *dev, long addr, int location, short value)
+{
+	int i;
+	int ee_addr = (typeof(ee_addr))addr;
+	short wren_cmd = EE_WrEnCmd | 0x30; /*wren is 100 + 11XXXX*/
+	short write_cmd = location | EE_WriteCmd;
+
+#ifdef NATSEMI_DEBUG
+	printf("write_eeprom: %08x, %04hx, %04hx\n",
+		dev->iobase + ee_addr, write_cmd, value);
+#endif
+	/* Shift the write enable command bits out. */
+	for (i = 9; i >= 0; i--) {
+		short cmdval = (wren_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+		OUTL(dev, cmdval, ee_addr);
+		eeprom_delay(ee_addr);
+		OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+
+	OUTL(dev, 0, ee_addr); /*bring chip select low*/
+	OUTL(dev, EE_ShiftClk, ee_addr);
+	eeprom_delay(ee_addr);
+
+	/* Shift the write command bits out. */
+	for (i = 9; i >= 0; i--) {
+		short cmdval = (write_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+		OUTL(dev, cmdval, ee_addr);
+		eeprom_delay(ee_addr);
+		OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+
+	for (i = 0; i < 16; i++) {
+		short cmdval = (value & (1 << i)) ? EE_Write1 : EE_Write0;
+		OUTL(dev, cmdval, ee_addr);
+		eeprom_delay(ee_addr);
+		OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+
+	OUTL(dev, 0, ee_addr); /*bring chip select low*/
+	OUTL(dev, EE_ShiftClk, ee_addr);
+	for (i = 0; i < 200000; i++) {
+		OUTL(dev, EE_Write0, ee_addr); /*poll for done*/
+		if (INL(dev, ee_addr) & EE_DataOut) {
+		    break; /*finished*/
+		}
+	}
+	eeprom_delay(ee_addr);
+
+	/* Terminate the EEPROM access. */
+	OUTL(dev, EE_Write0, ee_addr);
+	OUTL(dev, 0, ee_addr);
+	return;
+}
+#endif
+
+static int
+read_eeprom(struct eth_device *dev, long addr, int location)
+{
+	int i;
+	int retval = 0;
+	int ee_addr = (typeof(ee_addr))addr;
+	int read_cmd = location | EE_ReadCmd;
+
+	OUTL(dev, EE_Write0, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+		OUTL(dev, dataval, ee_addr);
+		eeprom_delay(ee_addr);
+		OUTL(dev, dataval | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+	OUTL(dev, EE_ChipSelect, ee_addr);
+	eeprom_delay(ee_addr);
+
+	for (i = 0; i < 16; i++) {
+		OUTL(dev, EE_ChipSelect | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+		retval |= (INL(dev, ee_addr) & EE_DataOut) ? 1 << i : 0;
+		OUTL(dev, EE_ChipSelect, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+
+	/* Terminate the EEPROM access. */
+	OUTL(dev, EE_Write0, ee_addr);
+	OUTL(dev, 0, ee_addr);
+#ifdef NATSEMI_DEBUG
+	if (natsemi_debug)
+		printf("read_eeprom: %08x, %08x, retval %08x\n",
+			dev->iobase + ee_addr, read_cmd, retval);
+#endif
+	return retval;
+}
+
+/*  MII transceiver control section.
+	The 83815 series has an internal transceiver, and we present the
+	management registers as if they were MII connected. */
+
+static int
+mdio_read(struct eth_device *dev, int phy_id, int location)
+{
+	if (phy_id == 1 && location < 32)
+		return INL(dev, BasicControl+(location<<2))&0xffff;
+	else
+		return 0xffff;
+}
+
+/* Function: natsemi_init
+ *
+ * Description: resets the ethernet controller chip and configures
+ *    registers and data structures required for sending and receiving packets.
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * returns:  	int.
+ */
+
+static int
+natsemi_init(struct eth_device *dev, bd_t * bis)
+{
+
+	natsemi_reset(dev);
+
+	/* Disable PME:
+	 * The PME bit is initialized from the EEPROM contents.
+	 * PCI cards probably have PME disabled, but motherboard
+	 * implementations may have PME set to enable WakeOnLan.
+	 * With PME set the chip will scan incoming packets but
+	 * nothing will be written to memory. */
+	OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+	natsemi_init_rxfilter(dev);
+	natsemi_init_txd(dev);
+	natsemi_init_rxd(dev);
+
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+	tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | (0x1002);
+	rx_config = RxMxdma_256 | 0x20;
+
+#ifdef NATSEMI_DEBUG
+	printf("%s: Setting TxConfig Register %#08X\n", dev->name, tx_config);
+	printf("%s: Setting RxConfig Register %#08X\n", dev->name, rx_config);
+#endif
+	OUTL(dev, tx_config, TxConfig);
+	OUTL(dev, rx_config, RxConfig);
+
+	natsemi_check_duplex(dev);
+	natsemi_set_rx_mode(dev);
+
+	OUTL(dev, (RxOn | TxOn), ChipCmd);
+	return 1;
+}
+
+/*
+ * Function: natsemi_reset
+ *
+ * Description: soft resets the controller chip
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * Returns:   void.
+ */
+static void
+natsemi_reset(struct eth_device *dev)
+{
+	OUTL(dev, ChipReset, ChipCmd);
+
+	/* On page 78 of the spec, they recommend some settings for "optimum
+	   performance" to be done in sequence.  These settings optimize some
+	   of the 100Mbit autodetection circuitry.  Also, we only want to do
+	   this for rev C of the chip.  */
+	if (INL(dev, SiliconRev) == 0x302) {
+		OUTW(dev, 0x0001, PGSEL);
+		OUTW(dev, 0x189C, PMDCSR);
+		OUTW(dev, 0x0000, TSTDAT);
+		OUTW(dev, 0x5040, DSPCFG);
+		OUTW(dev, 0x008C, SDCFG);
+	}
+	/* Disable interrupts using the mask. */
+	OUTL(dev, 0, IntrMask);
+	OUTL(dev, 0, IntrEnable);
+}
+
+/* Function: natsemi_init_rxfilter
+ *
+ * Description: sets receive filter address to our MAC address
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * returns:   void.
+ */
+
+static void
+natsemi_init_rxfilter(struct eth_device *dev)
+{
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		OUTL(dev, i, RxFilterAddr);
+		OUTW(dev, dev->enetaddr[i] + (dev->enetaddr[i + 1] << 8),
+		     RxFilterData);
+	}
+}
+
+/*
+ * Function: natsemi_init_txd
+ *
+ * Description: initializes the Tx descriptor
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * returns:   void.
+ */
+
+static void
+natsemi_init_txd(struct eth_device *dev)
+{
+	txd.link = (u32) 0;
+	txd.cmdsts = (u32) 0;
+	txd.bufptr = (u32) & txb[0];
+
+	/* load Transmit Descriptor Register */
+	OUTL(dev, (u32) & txd, TxRingPtr);
+#ifdef NATSEMI_DEBUG
+	printf("natsemi_init_txd: TX descriptor reg loaded with: %#08X\n",
+	       INL(dev, TxRingPtr));
+#endif
+}
+
+/* Function: natsemi_init_rxd
+ *
+ * Description: initializes the Rx descriptor ring
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+natsemi_init_rxd(struct eth_device *dev)
+{
+	int i;
+
+	cur_rx = 0;
+
+	/* init RX descriptor */
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		rxd[i].link =
+		    cpu_to_le32((i + 1 <
+				 NUM_RX_DESC) ? (u32) & rxd[i +
+							    1] : (u32) &
+				rxd[0]);
+		rxd[i].cmdsts = cpu_to_le32((u32) RX_BUF_SIZE);
+		rxd[i].bufptr = cpu_to_le32((u32) & rxb[i * RX_BUF_SIZE]);
+#ifdef NATSEMI_DEBUG
+		printf
+		    ("natsemi_init_rxd: rxd[%d]=%p link=%X cmdsts=%lX bufptr=%X\n",
+		     	i, &rxd[i], le32_to_cpu(rxd[i].link),
+		     		rxd[i].cmdsts, rxd[i].bufptr);
+#endif
+	}
+
+	/* load Receive Descriptor Register */
+	OUTL(dev, (u32) & rxd[0], RxRingPtr);
+
+#ifdef NATSEMI_DEBUG
+	printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
+	       INL(dev, RxRingPtr));
+#endif
+}
+
+/* Function: natsemi_set_rx_mode
+ *
+ * Description:
+ *    sets the receive mode to accept all broadcast packets and packets
+ *    with our MAC address, and reject all multicast packets.
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+natsemi_set_rx_mode(struct eth_device *dev)
+{
+	u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
+
+	OUTL(dev, rx_mode, RxFilterAddr);
+}
+
+static void
+natsemi_check_duplex(struct eth_device *dev)
+{
+	int duplex = INL(dev, ChipConfig) & FullDuplex ? 1 : 0;
+
+#ifdef NATSEMI_DEBUG
+	printf("%s: Setting %s-duplex based on negotiated link"
+	       " capability.\n", dev->name, duplex ? "full" : "half");
+#endif
+	if (duplex) {
+		rx_config |= RxAcceptTx;
+		tx_config |= (TxCarrierIgn | TxHeartIgn);
+	} else {
+		rx_config &= ~RxAcceptTx;
+		tx_config &= ~(TxCarrierIgn | TxHeartIgn);
+	}
+	OUTL(dev, tx_config, TxConfig);
+	OUTL(dev, rx_config, RxConfig);
+}
+
+/* Function: natsemi_send
+ *
+ * Description: transmits a packet and waits for completion or timeout.
+ *
+ * Returns:   void.  */
+static int
+natsemi_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	u32 i, status = 0;
+	u32 tx_status = 0;
+	vu_long *res = (vu_long *)&tx_status;
+
+	/* Stop the transmitter */
+	OUTL(dev, TxOff, ChipCmd);
+
+#ifdef NATSEMI_DEBUG
+	if (natsemi_debug)
+		printf("natsemi_send: sending %d bytes\n", (int) length);
+#endif
+
+	/* set the transmit buffer descriptor and enable Transmit State Machine */
+	txd.link = cpu_to_le32(0);
+	txd.bufptr = cpu_to_le32(phys_to_bus((u32) packet));
+	txd.cmdsts = cpu_to_le32(DescOwn | length);
+
+	/* load Transmit Descriptor Register */
+	OUTL(dev, phys_to_bus((u32) & txd), TxRingPtr);
+#ifdef NATSEMI_DEBUG
+	if (natsemi_debug)
+	    printf("natsemi_send: TX descriptor register loaded with: %#08X\n",
+	     INL(dev, TxRingPtr));
+#endif
+	/* restart the transmitter */
+	OUTL(dev, TxOn, ChipCmd);
+
+	for (i = 0;
+	     (*res = le32_to_cpu(txd.cmdsts)) & DescOwn;
+	     i++) {
+		if (i >= TOUT_LOOP) {
+			printf
+			    ("%s: tx error buffer not ready: txd.cmdsts == %#X\n",
+			     dev->name, tx_status);
+			goto Done;
+		}
+	}
+
+	if (!(tx_status & DescPktOK)) {
+		printf("natsemi_send: Transmit error, Tx status %X.\n",
+		       tx_status);
+		goto Done;
+	}
+
+	status = 1;
+      Done:
+	return status;
+}
+
+/* Function: natsemi_poll
+ *
+ * Description: checks for a received packet and returns it if found.
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * Returns:   1 if    packet was received.
+ *            0 if no packet was received.
+ *
+ * Side effects:
+ *            Returns (copies) the packet to the array dev->packet.
+ *            Returns the length of the packet.
+ */
+
+static int
+natsemi_poll(struct eth_device *dev)
+{
+	int retstat = 0;
+	int length = 0;
+	u32 rx_status = le32_to_cpu(rxd[cur_rx].cmdsts);
+
+	if (!(rx_status & (u32) DescOwn))
+		return retstat;
+#ifdef NATSEMI_DEBUG
+	if (natsemi_debug)
+		printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
+		       cur_rx, rx_status);
+#endif
+	length = (rx_status & DSIZE) - CRC_SIZE;
+
+	if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
+		printf
+		    ("natsemi_poll: Corrupted packet received, buffer status = %X\n",
+		     rx_status);
+		retstat = 0;
+	} else {		/* give packet to higher level routine */
+		NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+		retstat = 1;
+	}
+
+	/* return the descriptor and buffer to receive ring */
+	rxd[cur_rx].cmdsts = cpu_to_le32(RX_BUF_SIZE);
+	rxd[cur_rx].bufptr = cpu_to_le32((u32) & rxb[cur_rx * RX_BUF_SIZE]);
+
+	if (++cur_rx == NUM_RX_DESC)
+		cur_rx = 0;
+
+	/* re-enable the potentially idle receive state machine */
+	OUTL(dev, RxOn, ChipCmd);
+
+	return retstat;
+}
+
+/* Function: natsemi_disable
+ *
+ * Description: Turns off interrupts and stops Tx and Rx engines
+ *
+ * Arguments: struct eth_device *dev:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+natsemi_disable(struct eth_device *dev)
+{
+	/* Disable interrupts using the mask. */
+	OUTL(dev, 0, IntrMask);
+	OUTL(dev, 0, IntrEnable);
+
+	/* Stop the chip's Tx and Rx processes. */
+	OUTL(dev, RxOff | TxOff, ChipCmd);
+
+	/* Restore PME enable bit */
+	OUTL(dev, SavedClkRun, ClkRun);
+}
+
+#endif
diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c
new file mode 100644
index 0000000..c978d62
--- /dev/null
+++ b/drivers/net/ne2000.c
@@ -0,0 +1,940 @@
+/*
+Ported to U-Boot  by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+
+==========================================================================
+
+dev/if_dp83902a.c
+
+Ethernet device driver for NS DP83902a ethernet controller
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+-------------------------------------------
+This file is part of eCos, the Embedded Configurable Operating System.
+Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+eCos 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 or (at your option) any later version.
+
+eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with eCos; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file does not
+by itself cause the resulting work to be covered by the GNU General Public
+License. However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based on
+this file might be covered by the GNU General Public License.
+
+Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+at http://sources.redhat.com/ecos/ecos-license/
+-------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+-------------------------------------------
+
+Portions of this software may have been derived from OpenBSD or other sources,
+and are covered by the appropriate copyright disclaimers included herein.
+
+-------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+Author(s):    gthomas
+Contributors: gthomas, jskov, rsandifo
+Date:	      2001-06-13
+Purpose:
+Description:
+
+FIXME:	      Will fail if pinged with large packets (1520 bytes)
+Add promisc config
+Add SNMP
+
+####DESCRIPTIONEND####
+
+
+==========================================================================
+
+*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+
+#ifdef CONFIG_DRIVER_NE2000
+
+/* wor around udelay resetting OCR */
+static void my_udelay(long us) {
+	long tmo;
+
+	tmo = get_timer (0) + us * CFG_HZ / 1000000; /* will this be much greater than 0 ? */
+	while (get_timer (0) < tmo);
+}
+
+#define mdelay(n)       my_udelay((n)*1000)
+
+/* forward definition of function used for the uboot interface */
+void uboot_push_packet_len(int len);
+void uboot_push_tx_done(int key, int val);
+
+/* timeout for tx/rx in s */
+#define TOUT 5
+
+#define ETHER_ADDR_LEN 6
+
+/*
+  ------------------------------------------------------------------------
+  Debugging details
+
+  Set to perms of:
+  0 disables all debug output
+  1 for process debug output
+  2 for added data IO output: get_reg, put_reg
+  4 for packet allocation/free output
+  8 for only startup status, so we can tell we're installed OK
+*/
+/*#define DEBUG 0xf*/
+#define DEBUG 0
+
+#if DEBUG & 1
+#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
+#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
+#else
+#define DEBUG_FUNCTION() do {} while(0)
+#define DEBUG_LINE() do {} while(0)
+#endif
+
+#include "ne2000.h"
+
+#if DEBUG & 1
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+static dp83902a_priv_data_t nic; /* just one instance of the card supported */
+
+static bool
+dp83902a_init(void)
+{
+	dp83902a_priv_data_t *dp = &nic;
+	cyg_uint8* base;
+	int i;
+
+	DEBUG_FUNCTION();
+
+	base = dp->base;
+	if (!base) return false;  /* No device found */
+
+	DEBUG_LINE();
+
+	/* Prepare ESA */
+	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);  /* Select page 1 */
+	/* Use the address from the serial EEPROM */
+	for (i = 0; i < 6; i++)
+		DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
+	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);  /* Select page 0 */
+
+	printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       "eeprom",
+	       dp->esa[0],
+	       dp->esa[1],
+	       dp->esa[2],
+	       dp->esa[3],
+	       dp->esa[4],
+	       dp->esa[5] );
+
+	return true;
+}
+
+static void
+dp83902a_stop(void)
+{
+	dp83902a_priv_data_t *dp = &nic;
+	cyg_uint8 *base = dp->base;
+
+	DEBUG_FUNCTION();
+
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);  /* Brutal */
+	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
+	DP_OUT(base, DP_IMR, 0x00);		/* Disable all interrupts */
+
+	dp->running = false;
+}
+
+/*
+  This function is called to "start up" the interface.  It may be called
+  multiple times, even when the hardware is already running.  It will be
+  called whenever something "hardware oriented" changes and should leave
+  the hardware ready to send/receive packets.
+*/
+static void
+dp83902a_start(unsigned char * enaddr)
+{
+	dp83902a_priv_data_t *dp = &nic;
+	cyg_uint8 *base = dp->base;
+	int i;
+
+	DEBUG_FUNCTION();
+
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
+	DP_OUT(base, DP_DCR, DP_DCR_INIT);
+	DP_OUT(base, DP_RBCH, 0);		/* Remote byte count */
+	DP_OUT(base, DP_RBCL, 0);
+	DP_OUT(base, DP_RCR, DP_RCR_MON);	/* Accept no packets */
+	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);	/* Transmitter [virtually] off */
+	DP_OUT(base, DP_TPSR, dp->tx_buf1);	/* Transmitter start page */
+	dp->tx1 = dp->tx2 = 0;
+	dp->tx_next = dp->tx_buf1;
+	dp->tx_started = false;
+	DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
+	DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); /* Receive ring boundary */
+	DP_OUT(base, DP_PSTOP, dp->rx_buf_end);	/* Receive ring end page */
+	dp->rx_next = dp->rx_buf_start-1;
+	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
+	DP_OUT(base, DP_IMR, DP_IMR_All);	/* Enable all interrupts */
+	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP);  /* Select page 1 */
+	DP_OUT(base, DP_P1_CURP, dp->rx_buf_start);   /* Current page - next free page for Rx */
+	for (i = 0;  i < ETHER_ADDR_LEN;  i++) {
+		DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
+	}
+	/* Enable and start device */
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+	DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
+	DP_OUT(base, DP_RCR, DP_RCR_AB);  /* Accept broadcast, no errors, no multicast */
+	dp->running = true;
+}
+
+/*
+  This routine is called to start the transmitter.  It is split out from the
+  data handling routine so it may be called either when data becomes first
+  available or when an Tx interrupt occurs
+*/
+
+static void
+dp83902a_start_xmit(int start_page, int len)
+{
+	dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
+	cyg_uint8 *base = dp->base;
+
+	DEBUG_FUNCTION();
+
+#if DEBUG & 1
+	printf("Tx pkt %d len %d\n", start_page, len);
+	if (dp->tx_started)
+		printf("TX already started?!?\n");
+#endif
+
+	DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+	DP_OUT(base, DP_TBCL, len & 0xFF);
+	DP_OUT(base, DP_TBCH, len >> 8);
+	DP_OUT(base, DP_TPSR, start_page);
+	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+
+	dp->tx_started = true;
+}
+
+/*
+  This routine is called to send data to the hardware.  It is known a-priori
+  that there is free buffer space (dp->tx_next).
+*/
+static void
+dp83902a_send(unsigned char *data, int total_len, unsigned long key)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	int len, start_page, pkt_len, i, isr;
+#if DEBUG & 4
+	int dx;
+#endif
+
+	DEBUG_FUNCTION();
+
+	len = pkt_len = total_len;
+	if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME;
+
+	start_page = dp->tx_next;
+	if (dp->tx_next == dp->tx_buf1) {
+		dp->tx1 = start_page;
+		dp->tx1_len = pkt_len;
+		dp->tx1_key = key;
+		dp->tx_next = dp->tx_buf2;
+	} else {
+		dp->tx2 = start_page;
+		dp->tx2_len = pkt_len;
+		dp->tx2_key = key;
+		dp->tx_next = dp->tx_buf1;
+	}
+
+#if DEBUG & 5
+	printf("TX prep page %d len %d\n", start_page, pkt_len);
+#endif
+
+	DP_OUT(base, DP_ISR, DP_ISR_RDC);  /* Clear end of DMA */
+	{
+		/* Dummy read. The manual sez something slightly different, */
+		/* but the code is extended a bit to do what Hitachi's monitor */
+		/* does (i.e., also read data). */
+
+		cyg_uint16 tmp;
+		int len = 1;
+
+		DP_OUT(base, DP_RSAL, 0x100-len);
+		DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);
+		DP_OUT(base, DP_RBCL, len);
+		DP_OUT(base, DP_RBCH, 0);
+		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
+		DP_IN_DATA(dp->data, tmp);
+	}
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+	/* Stall for a bit before continuing to work around random data */
+	/* corruption problems on some platforms. */
+	CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+	/* Send data to device buffer(s) */
+	DP_OUT(base, DP_RSAL, 0);
+	DP_OUT(base, DP_RSAH, start_page);
+	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
+	DP_OUT(base, DP_RBCH, pkt_len >> 8);
+	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
+
+	/* Put data into buffer */
+#if DEBUG & 4
+	printf(" sg buf %08lx len %08x\n ", (unsigned long) data, len);
+	dx = 0;
+#endif
+	while (len > 0) {
+#if DEBUG & 4
+		printf(" %02x", *data);
+		if (0 == (++dx % 16)) printf("\n ");
+#endif
+		DP_OUT_DATA(dp->data, *data++);
+		len--;
+	}
+#if DEBUG & 4
+	printf("\n");
+#endif
+	if (total_len < pkt_len) {
+#if DEBUG & 4
+		printf("  + %d bytes of padding\n", pkt_len - total_len);
+#endif
+		/* Padding to 802.3 length was required */
+		for (i = total_len;  i < pkt_len;) {
+			i++;
+			DP_OUT_DATA(dp->data, 0);
+		}
+	}
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+	/* After last data write, delay for a bit before accessing the */
+	/* device again, or we may get random data corruption in the last */
+	/* datum (on some platforms). */
+	CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+	/* Wait for DMA to complete */
+	do {
+		DP_IN(base, DP_ISR, isr);
+	} while ((isr & DP_ISR_RDC) == 0);
+	/* Then disable DMA */
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+
+	/* Start transmit if not already going */
+	if (!dp->tx_started) {
+		if (start_page == dp->tx1) {
+			dp->tx_int = 1;  /* Expecting interrupt from BUF1 */
+		} else {
+			dp->tx_int = 2;  /* Expecting interrupt from BUF2 */
+		}
+		dp83902a_start_xmit(start_page, pkt_len);
+	}
+}
+
+/*
+  This function is called when a packet has been received.  It's job is
+  to prepare to unload the packet from the hardware.  Once the length of
+  the packet is known, the upper layer of the driver can be told.  When
+  the upper layer is ready to unload the packet, the internal function
+  'dp83902a_recv' will be called to actually fetch it from the hardware.
+*/
+static void
+dp83902a_RxEvent(void)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	unsigned char rsr;
+	unsigned char rcv_hdr[4];
+	int i, len, pkt, cur;
+
+	DEBUG_FUNCTION();
+
+	DP_IN(base, DP_RSR, rsr);
+	while (true) {
+		/* Read incoming packet header */
+		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
+		DP_IN(base, DP_P1_CURP, cur);
+		DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+		DP_IN(base, DP_BNDRY, pkt);
+
+		pkt += 1;
+		if (pkt == dp->rx_buf_end)
+			pkt = dp->rx_buf_start;
+
+		if (pkt == cur) {
+			break;
+		}
+		DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
+		DP_OUT(base, DP_RBCH, 0);
+		DP_OUT(base, DP_RSAL, 0);
+		DP_OUT(base, DP_RSAH, pkt);
+		if (dp->rx_next == pkt) {
+			if (cur == dp->rx_buf_start)
+				DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
+			else
+				DP_OUT(base, DP_BNDRY, cur-1); /* Update pointer */
+			return;
+		}
+		dp->rx_next = pkt;
+		DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+		DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+		CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+		for (i = 0;  i < sizeof(rcv_hdr);) {
+			DP_IN_DATA(dp->data, rcv_hdr[i++]);
+		}
+
+#if DEBUG & 5
+		printf("rx hdr %02x %02x %02x %02x\n",
+		       rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
+#endif
+		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
+		uboot_push_packet_len(len);
+		if (rcv_hdr[1] == dp->rx_buf_start)
+			DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
+		else
+			DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); /* Update pointer */
+	}
+}
+
+/*
+  This function is called as a result of the "eth_drv_recv()" call above.
+  It's job is to actually fetch data for a packet from the hardware once
+  memory buffers have been allocated for the packet.  Note that the buffers
+  may come in pieces, using a scatter-gather list.  This allows for more
+  efficient processing in the upper layers of the stack.
+*/
+static void
+dp83902a_recv(unsigned char *data, int len)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	int i, mlen;
+	cyg_uint8 saved_char = 0;
+	bool saved;
+#if DEBUG & 4
+	int dx;
+#endif
+
+	DEBUG_FUNCTION();
+
+#if DEBUG & 5
+	printf("Rx packet %d length %d\n", dp->rx_next, len);
+#endif
+
+	/* Read incoming packet data */
+	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+	DP_OUT(base, DP_RBCL, len & 0xFF);
+	DP_OUT(base, DP_RBCH, len >> 8);
+	DP_OUT(base, DP_RSAL, 4);		/* Past header */
+	DP_OUT(base, DP_RSAH, dp->rx_next);
+	DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+	DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+	CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+	saved = false;
+	for (i = 0;  i < 1;  i++) {
+		if (data) {
+			mlen = len;
+#if DEBUG & 4
+			printf(" sg buf %08lx len %08x \n", (unsigned long) data, mlen);
+			dx = 0;
+#endif
+			while (0 < mlen) {
+				/* Saved byte from previous loop? */
+				if (saved) {
+					*data++ = saved_char;
+					mlen--;
+					saved = false;
+					continue;
+				}
+
+				{
+					cyg_uint8 tmp;
+					DP_IN_DATA(dp->data, tmp);
+#if DEBUG & 4
+					printf(" %02x", tmp);
+					if (0 == (++dx % 16)) printf("\n ");
+#endif
+					*data++ = tmp;;
+					mlen--;
+				}
+			}
+#if DEBUG & 4
+			printf("\n");
+#endif
+		}
+	}
+}
+
+static void
+dp83902a_TxEvent(void)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	unsigned char tsr;
+	unsigned long key;
+
+	DEBUG_FUNCTION();
+
+	DP_IN(base, DP_TSR, tsr);
+	if (dp->tx_int == 1) {
+		key = dp->tx1_key;
+		dp->tx1 = 0;
+	} else {
+		key = dp->tx2_key;
+		dp->tx2 = 0;
+	}
+	/* Start next packet if one is ready */
+	dp->tx_started = false;
+	if (dp->tx1) {
+		dp83902a_start_xmit(dp->tx1, dp->tx1_len);
+		dp->tx_int = 1;
+	} else if (dp->tx2) {
+		dp83902a_start_xmit(dp->tx2, dp->tx2_len);
+		dp->tx_int = 2;
+	} else {
+		dp->tx_int = 0;
+	}
+	/* Tell higher level we sent this packet */
+	uboot_push_tx_done(key, 0);
+}
+
+/* Read the tally counters to clear them.  Called in response to a CNT */
+/* interrupt. */
+static void
+dp83902a_ClearCounters(void)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	cyg_uint8 cnt1, cnt2, cnt3;
+
+	DP_IN(base, DP_FER, cnt1);
+	DP_IN(base, DP_CER, cnt2);
+	DP_IN(base, DP_MISSED, cnt3);
+	DP_OUT(base, DP_ISR, DP_ISR_CNT);
+}
+
+/* Deal with an overflow condition.  This code follows the procedure set */
+/* out in section 7.0 of the datasheet. */
+static void
+dp83902a_Overflow(void)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
+	cyg_uint8 *base = dp->base;
+	cyg_uint8 isr;
+
+	/* Issue a stop command and wait 1.6ms for it to complete. */
+	DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
+	CYGACC_CALL_IF_DELAY_US(1600);
+
+	/* Clear the remote byte counter registers. */
+	DP_OUT(base, DP_RBCL, 0);
+	DP_OUT(base, DP_RBCH, 0);
+
+	/* Enter loopback mode while we clear the buffer. */
+	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
+	DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
+
+	/* Read in as many packets as we can and acknowledge any and receive */
+	/* interrupts.  Since the buffer has overflowed, a receive event of */
+	/* some kind will have occured. */
+	dp83902a_RxEvent();
+	DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
+
+	/* Clear the overflow condition and leave loopback mode. */
+	DP_OUT(base, DP_ISR, DP_ISR_OFLW);
+	DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
+
+	/* If a transmit command was issued, but no transmit event has occured, */
+	/* restart it here. */
+	DP_IN(base, DP_ISR, isr);
+	if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
+		DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+	}
+}
+
+static void
+dp83902a_poll(void)
+{
+	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+	cyg_uint8 *base = dp->base;
+	unsigned char isr;
+
+	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
+	DP_IN(base, DP_ISR, isr);
+	while (0 != isr) {
+		/* The CNT interrupt triggers when the MSB of one of the error */
+		/* counters is set.  We don't much care about these counters, but */
+		/* we should read their values to reset them. */
+		if (isr & DP_ISR_CNT) {
+			dp83902a_ClearCounters();
+		}
+		/* Check for overflow.  It's a special case, since there's a */
+		/* particular procedure that must be followed to get back into */
+		/* a running state.a */
+		if (isr & DP_ISR_OFLW) {
+			dp83902a_Overflow();
+		} else {
+			/* Other kinds of interrupts can be acknowledged simply by */
+			/* clearing the relevant bits of the ISR.  Do that now, then */
+			/* handle the interrupts we care about. */
+			DP_OUT(base, DP_ISR, isr);      /* Clear set bits */
+			if (!dp->running) break;	/* Is this necessary? */
+			/* Check for tx_started on TX event since these may happen */
+			/* spuriously it seems. */
+			if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
+				dp83902a_TxEvent();
+			}
+			if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
+				dp83902a_RxEvent();
+			}
+		}
+		DP_IN(base, DP_ISR, isr);
+	}
+}
+
+/* find prom (taken from pc_net_cs.c from Linux) */
+
+#include "8390.h"
+
+typedef struct hw_info_t {
+	u_int	offset;
+	u_char	a0, a1, a2;
+	u_int	flags;
+} hw_info_t;
+
+#define DELAY_OUTPUT	0x01
+#define HAS_MISC_REG	0x02
+#define USE_BIG_BUF	0x04
+#define HAS_IBM_MISC	0x08
+#define IS_DL10019	0x10
+#define IS_DL10022	0x20
+#define HAS_MII		0x40
+#define USE_SHMEM	0x80	/* autodetected */
+
+#define AM79C9XX_HOME_PHY	0x00006B90  /* HomePNA PHY */
+#define AM79C9XX_ETH_PHY	0x00006B70  /* 10baseT PHY */
+#define MII_PHYID_REV_MASK	0xfffffff0
+#define MII_PHYID_REG1		0x02
+#define MII_PHYID_REG2		0x03
+
+static hw_info_t hw_info[] = {
+	{ /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
+	{ /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
+	{ /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
+	{ /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
+	  DELAY_OUTPUT | HAS_IBM_MISC },
+	{ /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
+	{ /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
+	{ /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
+	{ /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
+	{ /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
+	{ /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
+	{ /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
+	{ /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
+	{ /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
+	{ /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
+	{ /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
+	{ /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
+	{ /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
+	{ /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
+	{ /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
+	  HAS_MISC_REG | HAS_IBM_MISC },
+	{ /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
+	{ /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
+	{ /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
+	{ /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
+	  DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+	{ /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
+	{ /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
+	{ /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
+	{ /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
+	{ /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
+	{ /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 }
+};
+
+#define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
+
+static hw_info_t default_info = { 0, 0, 0, 0, 0 };
+
+unsigned char dev_addr[6];
+
+#define PCNET_CMD	0x00
+#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
+
+unsigned long nic_base;
+
+static void pcnet_reset_8390(void)
+{
+	int i, r;
+
+	PRINTK("nic base is %lx\n", nic_base);
+
+	n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
+	PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
+	n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
+	PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
+	n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
+	PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
+	n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
+
+	n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
+
+	for (i = 0; i < 100; i++) {
+		if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0)
+			break;
+		PRINTK("got %x in reset\n", r);
+		my_udelay(100);
+	}
+	n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */
+
+	if (i == 100)
+		printf("pcnet_reset_8390() did not complete.\n");
+} /* pcnet_reset_8390 */
+
+static hw_info_t * get_prom(void ) {
+	unsigned char prom[32];
+	int i, j;
+	struct {
+		u_char value, offset;
+	} program_seq[] = {
+		{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+		{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
+		{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+		{0x00,	EN0_RCNTHI},
+		{0x00,	EN0_IMR},	/* Mask completion irq. */
+		{0xFF,	EN0_ISR},
+		{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+		{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+		{32,	EN0_RCNTLO},
+		{0x00,	EN0_RCNTHI},
+		{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+		{0x00,	EN0_RSARHI},
+		{E8390_RREAD+E8390_START, E8390_CMD},
+	};
+
+	PRINTK("trying to get MAC via prom reading\n");
+
+	pcnet_reset_8390();
+
+	mdelay(10);
+
+	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+		n2k_outb(program_seq[i].value, program_seq[i].offset);
+
+	PRINTK("PROM:");
+	for (i = 0; i < 32; i++) {
+		prom[i] = n2k_inb(PCNET_DATAPORT);
+		PRINTK(" %02x", prom[i]);
+	}
+	PRINTK("\n");
+	for (i = 0; i < NR_INFO; i++) {
+		if ((prom[0] == hw_info[i].a0) &&
+		    (prom[2] == hw_info[i].a1) &&
+		    (prom[4] == hw_info[i].a2)) {
+			PRINTK("matched board %d\n", i);
+			break;
+		}
+	}
+	if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
+		for (j = 0; j < 6; j++)
+			dev_addr[j] = prom[j<<1];
+		PRINTK("on exit i is %d/%ld\n", i, NR_INFO);
+		PRINTK("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       dev_addr[0],dev_addr[1],dev_addr[2],dev_addr[3],dev_addr[4],dev_addr[5]);
+		return (i < NR_INFO) ? hw_info+i : &default_info;
+	}
+	return NULL;
+}
+
+/* U-boot specific routines */
+
+
+static unsigned char *pbuf = NULL;
+
+static int pkey = -1;
+static int initialized=0;
+
+void uboot_push_packet_len(int len) {
+	PRINTK("pushed len = %d\n", len);
+	if (len>=2000) {
+		printf("NE2000: packet too big\n");
+		return;
+	}
+	dp83902a_recv(&pbuf[0], len);
+
+	/*Just pass it to the upper layer*/
+	NetReceive(&pbuf[0], len);
+}
+
+void uboot_push_tx_done(int key, int val) {
+	PRINTK("pushed key = %d\n", key);
+	pkey = key;
+}
+
+int eth_init(bd_t *bd) {
+	static hw_info_t * r;
+	char ethaddr[20];
+
+	PRINTK("### eth_init\n");
+
+	if (!pbuf) {
+		pbuf = malloc(2000);
+		if (!pbuf) {
+			printf("Cannot allocate rx buffer\n");
+			return -1;
+		}
+	}
+
+#ifdef CONFIG_DRIVER_NE2000_CCR
+	{
+		volatile unsigned char *p =  (volatile unsigned char *) CONFIG_DRIVER_NE2000_CCR;
+
+		PRINTK("CCR before is %x\n", *p);
+		*p = CONFIG_DRIVER_NE2000_VAL;
+		PRINTK("CCR after is %x\n", *p);
+	}
+#endif
+
+	nic_base = CONFIG_DRIVER_NE2000_BASE;
+	nic.base = (cyg_uint8 *) CONFIG_DRIVER_NE2000_BASE;
+
+	r = get_prom();
+	if (!r)
+		return -1;
+
+	sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+		 dev_addr[0], dev_addr[1],
+		 dev_addr[2], dev_addr[3],
+		 dev_addr[4], dev_addr[5]) ;
+	PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
+	setenv ("ethaddr", ethaddr);
+
+
+#define DP_DATA		0x10
+	nic.data = nic.base + DP_DATA;
+	nic.tx_buf1 = 0x40;
+	nic.tx_buf2 = 0x48;
+	nic.rx_buf_start = 0x50;
+	nic.rx_buf_end = 0x80;
+
+	if (dp83902a_init() == false)
+		return -1;
+	dp83902a_start(dev_addr);
+	initialized=1;
+	return 0;
+}
+
+void eth_halt() {
+
+	PRINTK("### eth_halt\n");
+	if(initialized)
+		dp83902a_stop();
+	initialized=0;
+}
+
+int eth_rx() {
+dp83902a_poll();
+return 1;
+}
+
+int eth_send(volatile void *packet, int length) {
+	int tmo;
+
+	PRINTK("### eth_send\n");
+
+	pkey = -1;
+
+	dp83902a_send((unsigned char *) packet, length, 666);
+	tmo = get_timer (0) + TOUT * CFG_HZ;
+	while(1) {
+		dp83902a_poll();
+		if (pkey != -1) {
+			PRINTK("Packet sucesfully sent\n");
+			return 0;
+		}
+		if (get_timer (0) >= tmo) {
+			printf("transmission error (timoeut)\n");
+			return 0;
+		}
+
+	}
+	return 0;
+}
+#endif
diff --git a/drivers/net/ne2000.h b/drivers/net/ne2000.h
new file mode 100644
index 0000000..c13d9f0b
--- /dev/null
+++ b/drivers/net/ne2000.h
@@ -0,0 +1,279 @@
+/*
+Ported to U-Boot  by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+
+==========================================================================
+
+      dev/dp83902a.h
+
+      National Semiconductor DP83902a ethernet chip
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+ -------------------------------------------
+ This file is part of eCos, the Embedded Configurable Operating System.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ eCos 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 or (at your option) any later version.
+
+ eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with eCos; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+
+ Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+ at http://sources.redhat.com/ecos/ecos-license/
+ -------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+ -------------------------------------------
+
+ Portions of this software may have been derived from OpenBSD or other sources,
+ and are covered by the appropriate copyright disclaimers included herein.
+
+ -------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+ Author(s):    gthomas
+ Contributors: gthomas, jskov
+ Date:         2001-06-13
+ Purpose:
+ Description:
+
+####DESCRIPTIONEND####
+
+==========================================================================
+
+*/
+
+/*
+ ------------------------------------------------------------------------
+ Macros for accessing DP registers
+ These can be overridden by the platform header
+*/
+
+#define DP_IN(_b_, _o_, _d_)  (_d_) = *( (volatile unsigned char *) ((_b_)+(_o_)))
+#define DP_OUT(_b_, _o_, _d_) *( (volatile unsigned char *) ((_b_)+(_o_))) = (_d_)
+
+#define DP_IN_DATA(_b_, _d_)  (_d_) = *( (volatile unsigned char *) ((_b_)))
+#define DP_OUT_DATA(_b_, _d_) *( (volatile unsigned char *) ((_b_))) = (_d_)
+
+
+/* here is all the data */
+
+#define cyg_uint8 unsigned char
+#define cyg_uint16 unsigned short
+#define bool int
+
+#define false 0
+#define true 1
+
+#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 1
+#define CYGACC_CALL_IF_DELAY_US(X) my_udelay(X)
+
+typedef struct dp83902a_priv_data {
+    cyg_uint8* base;
+    cyg_uint8* data;
+    cyg_uint8* reset;
+    int tx_next;           /* First free Tx page */
+    int tx_int;            /* Expecting interrupt from this buffer */
+    int rx_next;           /* First free Rx page */
+    int tx1, tx2;          /* Page numbers for Tx buffers */
+    unsigned long tx1_key, tx2_key;   /* Used to ack when packet sent */
+    int tx1_len, tx2_len;
+    bool tx_started, running, hardwired_esa;
+    cyg_uint8 esa[6];
+    void* plf_priv;
+
+    /* Buffer allocation */
+    int tx_buf1, tx_buf2;
+    int rx_buf_start, rx_buf_end;
+} dp83902a_priv_data_t;
+
+/*
+ ------------------------------------------------------------------------
+ Some forward declarations
+*/
+static void dp83902a_poll(void);
+
+/* ------------------------------------------------------------------------ */
+/* Register offsets */
+
+#define DP_CR          0x00
+#define DP_CLDA0       0x01
+#define DP_PSTART      0x01             /* write */
+#define DP_CLDA1       0x02
+#define DP_PSTOP       0x02             /* write */
+#define DP_BNDRY       0x03
+#define DP_TSR         0x04
+#define DP_TPSR        0x04             /* write */
+#define DP_NCR         0x05
+#define DP_TBCL        0x05             /* write */
+#define DP_FIFO        0x06
+#define DP_TBCH        0x06             /* write */
+#define DP_ISR         0x07
+#define DP_CRDA0       0x08
+#define DP_RSAL        0x08             /* write */
+#define DP_CRDA1       0x09
+#define DP_RSAH        0x09             /* write */
+#define DP_RBCL        0x0a             /* write */
+#define DP_RBCH        0x0b             /* write */
+#define DP_RSR         0x0c
+#define DP_RCR         0x0c             /* write */
+#define DP_FER         0x0d
+#define DP_TCR         0x0d             /* write */
+#define DP_CER         0x0e
+#define DP_DCR         0x0e             /* write */
+#define DP_MISSED      0x0f
+#define DP_IMR         0x0f             /* write */
+#define DP_DATAPORT    0x10             /* "eprom" data port */
+
+#define DP_P1_CR       0x00
+#define DP_P1_PAR0     0x01
+#define DP_P1_PAR1     0x02
+#define DP_P1_PAR2     0x03
+#define DP_P1_PAR3     0x04
+#define DP_P1_PAR4     0x05
+#define DP_P1_PAR5     0x06
+#define DP_P1_CURP     0x07
+#define DP_P1_MAR0     0x08
+#define DP_P1_MAR1     0x09
+#define DP_P1_MAR2     0x0a
+#define DP_P1_MAR3     0x0b
+#define DP_P1_MAR4     0x0c
+#define DP_P1_MAR5     0x0d
+#define DP_P1_MAR6     0x0e
+#define DP_P1_MAR7     0x0f
+
+#define DP_P2_CR       0x00
+#define DP_P2_PSTART   0x01
+#define DP_P2_CLDA0    0x01             /* write */
+#define DP_P2_PSTOP    0x02
+#define DP_P2_CLDA1    0x02             /* write */
+#define DP_P2_RNPP     0x03
+#define DP_P2_TPSR     0x04
+#define DP_P2_LNPP     0x05
+#define DP_P2_ACH      0x06
+#define DP_P2_ACL      0x07
+#define DP_P2_RCR      0x0c
+#define DP_P2_TCR      0x0d
+#define DP_P2_DCR      0x0e
+#define DP_P2_IMR      0x0f
+
+/* Command register - common to all pages */
+
+#define DP_CR_STOP    0x01   /* Stop: software reset */
+#define DP_CR_START   0x02   /* Start: initialize device */
+#define DP_CR_TXPKT   0x04   /* Transmit packet */
+#define DP_CR_RDMA    0x08   /* Read DMA  (recv data from device) */
+#define DP_CR_WDMA    0x10   /* Write DMA (send data to device) */
+#define DP_CR_SEND    0x18   /* Send packet */
+#define DP_CR_NODMA   0x20   /* Remote (or no) DMA */
+#define DP_CR_PAGE0   0x00   /* Page select */
+#define DP_CR_PAGE1   0x40
+#define DP_CR_PAGE2   0x80
+#define DP_CR_PAGEMSK 0x3F   /* Used to mask out page bits */
+
+/* Data configuration register */
+
+#define DP_DCR_WTS    0x01   /* 1=16 bit word transfers */
+#define DP_DCR_BOS    0x02   /* 1=Little Endian */
+#define DP_DCR_LAS    0x04   /* 1=Single 32 bit DMA mode */
+#define DP_DCR_LS     0x08   /* 1=normal mode, 0=loopback */
+#define DP_DCR_ARM    0x10   /* 0=no send command (program I/O) */
+#define DP_DCR_FIFO_1 0x00   /* FIFO threshold */
+#define DP_DCR_FIFO_2 0x20
+#define DP_DCR_FIFO_4 0x40
+#define DP_DCR_FIFO_6 0x60
+
+#define DP_DCR_INIT   (DP_DCR_LS|DP_DCR_FIFO_4)
+
+/* Interrupt status register */
+
+#define DP_ISR_RxP    0x01   /* Packet received */
+#define DP_ISR_TxP    0x02   /* Packet transmitted */
+#define DP_ISR_RxE    0x04   /* Receive error */
+#define DP_ISR_TxE    0x08   /* Transmit error */
+#define DP_ISR_OFLW   0x10   /* Receive overflow */
+#define DP_ISR_CNT    0x20   /* Tally counters need emptying */
+#define DP_ISR_RDC    0x40   /* Remote DMA complete */
+#define DP_ISR_RESET  0x80   /* Device has reset (shutdown, error) */
+
+/* Interrupt mask register */
+
+#define DP_IMR_RxP    0x01   /* Packet received */
+#define DP_IMR_TxP    0x02   /* Packet transmitted */
+#define DP_IMR_RxE    0x04   /* Receive error */
+#define DP_IMR_TxE    0x08   /* Transmit error */
+#define DP_IMR_OFLW   0x10   /* Receive overflow */
+#define DP_IMR_CNT    0x20   /* Tall counters need emptying */
+#define DP_IMR_RDC    0x40   /* Remote DMA complete */
+
+#define DP_IMR_All    0x3F   /* Everything but remote DMA */
+
+/* Receiver control register */
+
+#define DP_RCR_SEP    0x01   /* Save bad(error) packets */
+#define DP_RCR_AR     0x02   /* Accept runt packets */
+#define DP_RCR_AB     0x04   /* Accept broadcast packets */
+#define DP_RCR_AM     0x08   /* Accept multicast packets */
+#define DP_RCR_PROM   0x10   /* Promiscuous mode */
+#define DP_RCR_MON    0x20   /* Monitor mode - 1=accept no packets */
+
+/* Receiver status register */
+
+#define DP_RSR_RxP    0x01   /* Packet received */
+#define DP_RSR_CRC    0x02   /* CRC error */
+#define DP_RSR_FRAME  0x04   /* Framing error */
+#define DP_RSR_FO     0x08   /* FIFO overrun */
+#define DP_RSR_MISS   0x10   /* Missed packet */
+#define DP_RSR_PHY    0x20   /* 0=pad match, 1=mad match */
+#define DP_RSR_DIS    0x40   /* Receiver disabled */
+#define DP_RSR_DFR    0x80   /* Receiver processing deferred */
+
+/* Transmitter control register */
+
+#define DP_TCR_NOCRC  0x01   /* 1=inhibit CRC */
+#define DP_TCR_NORMAL 0x00   /* Normal transmitter operation */
+#define DP_TCR_LOCAL  0x02   /* Internal NIC loopback */
+#define DP_TCR_INLOOP 0x04   /* Full internal loopback */
+#define DP_TCR_OUTLOOP 0x08  /* External loopback */
+#define DP_TCR_ATD    0x10   /* Auto transmit disable */
+#define DP_TCR_OFFSET 0x20   /* Collision offset adjust */
+
+/* Transmit status register */
+
+#define DP_TSR_TxP    0x01   /* Packet transmitted */
+#define DP_TSR_COL    0x04   /* Collision (at least one) */
+#define DP_TSR_ABT    0x08   /* Aborted because of too many collisions */
+#define DP_TSR_CRS    0x10   /* Lost carrier */
+#define DP_TSR_FU     0x20   /* FIFO underrun */
+#define DP_TSR_CDH    0x40   /* Collision Detect Heartbeat */
+#define DP_TSR_OWC    0x80   /* Collision outside normal window */
+
+#define IEEE_8023_MAX_FRAME         1518    /* Largest possible ethernet frame */
+#define IEEE_8023_MIN_FRAME           64    /* Smallest possible ethernet frame */
diff --git a/drivers/net/netarm_eth.c b/drivers/net/netarm_eth.c
new file mode 100644
index 0000000..a99ee5d
--- /dev/null
+++ b/drivers/net/netarm_eth.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2004 IMMS gGmbH <www.imms.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * author(s): Thomas Elste, <info@elste.org>
+ *            (some parts derived from uCLinux Netarm Ethernet Driver)
+ */
+
+
+#include <common.h>
+
+#ifdef CONFIG_DRIVER_NETARMETH
+#include <command.h>
+#include <net.h>
+#include "netarm_eth.h"
+#include <asm/arch/netarm_registers.h>
+
+
+#if defined(CONFIG_CMD_NET)
+
+static int na_mii_poll_busy (void);
+
+static void na_get_mac_addr (void)
+{
+	unsigned short p[3];
+	char *m_addr;
+	char ethaddr[20];
+
+	m_addr = (char *) p;
+
+	p[0] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_1);
+	p[1] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_2);
+	p[2] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_3);
+
+	sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+		 m_addr[0], m_addr[1],
+		 m_addr[2], m_addr[3], m_addr[4], m_addr[5]);
+
+	printf ("HW-MAC Address:  %s\n", ethaddr);
+
+	/* set env, todo: check if already an adress is set */
+	setenv ("ethaddr", ethaddr);
+}
+
+
+static void na_mii_write (int reg, int value)
+{
+	int mii_addr;
+
+	/* Select register */
+	mii_addr = CFG_ETH_PHY_ADDR + reg;
+	SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
+	/* Write value */
+	SET_EADDR (NETARM_ETH_MII_WRITE, value);
+	na_mii_poll_busy ();
+}
+
+static unsigned int na_mii_read (int reg)
+{
+	int mii_addr, val;
+
+	/* Select register */
+	mii_addr = CFG_ETH_PHY_ADDR + reg;
+	SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
+	/* do one management cycle */
+	SET_EADDR (NETARM_ETH_MII_CMD,
+		   GET_EADDR (NETARM_ETH_MII_CMD) | NETARM_ETH_MIIC_RSTAT);
+	na_mii_poll_busy ();
+	/* Return read value */
+	val = GET_EADDR (NETARM_ETH_MII_READ);
+	return val;
+}
+
+static int na_mii_poll_busy (void)
+{
+	/* arm simple, non interrupt dependent timer */
+	reset_timer_masked ();
+	while (get_timer_masked () < NA_MII_POLL_BUSY_DELAY) {
+		if (!(GET_EADDR (NETARM_ETH_MII_IND) & NETARM_ETH_MIII_BUSY)) {
+			return 1;
+		}
+	}
+	printf ("na_mii_busy timeout\n");
+	return (0);
+}
+
+static int na_mii_identify_phy (void)
+{
+	int id_reg_a = 0;
+
+	/* get phy id register */
+	id_reg_a = na_mii_read (MII_PHY_ID);
+
+	if (id_reg_a == 0x0043) {
+		/* This must be an Enable or a Lucent LU3X31 PHY chip */
+		return 1;
+	} else if (id_reg_a == 0x0013) {
+		/* it is an Intel LXT971A */
+		return 1;
+	}
+	return (0);
+}
+
+static int na_mii_negotiate (void)
+{
+	int i = 0;
+
+	/* Enable auto-negotiation */
+	na_mii_write (MII_PHY_AUTONEGADV, 0x01e1);
+	/* FIXME: 0x01E1 is 100Mb half and full duplex, 0x0061 is 10Mb only */
+	/* Restart auto-negotiation */
+	na_mii_write (MII_PHY_CONTROL, 0x1200);
+
+	/* status register is 0xffff after setting the autoneg restart bit */
+	while (na_mii_read (MII_PHY_STATUS) == 0xffff) {
+		i++;
+	}
+
+	/* na_mii_read uses the timer already, so we can't use it again for
+	   timeout checking.
+	   Instead we just try some times.
+	 */
+	for (i = 0; i < 40000; i++) {
+		if ((na_mii_read (MII_PHY_STATUS) & 0x0024) == 0x0024) {
+			return 0;
+		}
+	}
+	/*
+	   printf("*Warning* autonegotiation timeout, status: 0x%x\n",na_mii_read(MII_PHY_STATUS));
+	 */
+	return (1);
+}
+
+static unsigned int na_mii_check_speed (void)
+{
+	unsigned int status;
+
+	/* Read Status register */
+	status = na_mii_read (MII_PHY_STATUS);
+	/* Check link status.  If 0, default to 100 Mbps. */
+	if ((status & 0x0004) == 0) {
+		printf ("*Warning* no link detected, set default speed to 100Mbs\n");
+		return 1;
+	} else {
+		if ((na_mii_read (17) & 0x4000) != 0) {
+			printf ("100Mbs link detected\n");
+			return 1;
+		} else {
+			printf ("10Mbs link detected\n");
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static int reset_eth (void)
+{
+	int pt;
+
+	na_get_mac_addr ();
+	pt = na_mii_identify_phy ();
+
+	/* reset the phy */
+	na_mii_write (MII_PHY_CONTROL, 0x8000);
+	reset_timer_masked ();
+	while (get_timer_masked () < NA_MII_NEGOTIATE_DELAY) {
+		if ((na_mii_read (MII_PHY_STATUS) & 0x8000) == 0) {
+			break;
+		}
+	}
+	if (get_timer_masked () >= NA_MII_NEGOTIATE_DELAY)
+		printf ("phy reset timeout\n");
+
+	/* set the PCS reg */
+	SET_EADDR (NETARM_ETH_PCS_CFG, NETARM_ETH_PCSC_CLKS_25M |
+		   NETARM_ETH_PCSC_ENJAB | NETARM_ETH_PCSC_NOCFR);
+
+	na_mii_negotiate ();
+	na_mii_check_speed ();
+
+	/* Delay 10 millisecond.  (Maybe this should be 1 second.) */
+	udelay (10000);
+
+	/* Turn receive on.
+	   Enable statistics register autozero on read.
+	   Do not insert MAC address on transmit.
+	   Do not enable special test modes.  */
+	SET_EADDR (NETARM_ETH_STL_CFG,
+		   (NETARM_ETH_STLC_AUTOZ | NETARM_ETH_STLC_RXEN));
+
+	/* Set the inter-packet gap delay to 0.96us for MII.
+	   The NET+ARM H/W Reference Guide indicates that the Back-to-back IPG
+	   Gap Timer Register should be set to 0x15 and the Non Back-to-back IPG
+	   Gap Timer Register should be set to 0x00000C12 for the MII PHY. */
+	SET_EADDR (NETARM_ETH_B2B_IPG_GAP_TMR, 0x15);
+	SET_EADDR (NETARM_ETH_NB2B_IPG_GAP_TMR, 0x00000C12);
+
+	/* Add CRC to end of packets.
+	   Pad packets to minimum length of 64 bytes.
+	   Allow unlimited length transmit packets.
+	   Receive all broadcast packets.
+	   NOTE:  Multicast addressing is NOT enabled here currently. */
+	SET_EADDR (NETARM_ETH_MAC_CFG,
+		   (NETARM_ETH_MACC_CRCEN |
+		    NETARM_ETH_MACC_PADEN | NETARM_ETH_MACC_HUGEN));
+	SET_EADDR (NETARM_ETH_SAL_FILTER, NETARM_ETH_SALF_BROAD);
+
+	/* enable fifos */
+	SET_EADDR (NETARM_ETH_GEN_CTRL,
+		   (NETARM_ETH_GCR_ERX | NETARM_ETH_GCR_ETX));
+
+	return (0);
+}
+
+
+extern int eth_init (bd_t * bd)
+{
+	reset_eth ();
+	return 0;
+}
+
+extern void eth_halt (void)
+{
+	SET_EADDR (NETARM_ETH_GEN_CTRL, 0);
+}
+
+/* Get a data block via Ethernet */
+extern int eth_rx (void)
+{
+	int i;
+	unsigned short rxlen;
+	unsigned int *addr;
+	unsigned int rxstatus, lastrxlen;
+	char *pa;
+
+	/* RXBR is 1, data block was received */
+	if ((GET_EADDR (NETARM_ETH_GEN_STAT) & NETARM_ETH_GST_RXBR) == 0)
+		return 0;
+
+	/* get status register and the length of received block */
+	rxstatus = GET_EADDR (NETARM_ETH_RX_STAT);
+	rxlen = (rxstatus & NETARM_ETH_RXSTAT_SIZE) >> 16;
+
+	if (rxlen == 0)
+		return 0;
+
+	/* clear RXBR to make fifo available */
+	SET_EADDR (NETARM_ETH_GEN_STAT,
+		   GET_EADDR (NETARM_ETH_GEN_STAT) & ~NETARM_ETH_GST_RXBR);
+
+	/* clear TXBC to make fifo available */
+	/* According to NETARM50 data manual you just have to clear
+	   RXBR but that has no effect. Only after clearing TXBC the
+	   Fifo becomes readable. */
+	SET_EADDR (NETARM_ETH_GEN_STAT,
+		   GET_EADDR (NETARM_ETH_GEN_STAT) & ~NETARM_ETH_GST_TXBC);
+
+	addr = (unsigned int *) NetRxPackets[0];
+	pa = (char *) NetRxPackets[0];
+
+	/* read the fifo */
+	for (i = 0; i < rxlen / 4; i++) {
+		*addr = GET_EADDR (NETARM_ETH_FIFO_DAT1);
+		addr++;
+	}
+
+	if (GET_EADDR (NETARM_ETH_GEN_STAT) & NETARM_ETH_GST_RXREGR) {
+		/* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */
+		lastrxlen =
+			(GET_EADDR (NETARM_ETH_GEN_STAT) &
+			 NETARM_ETH_GST_RXFDB) >> 28;
+		*addr = GET_EADDR (NETARM_ETH_FIFO_DAT1);
+		switch (lastrxlen) {
+		case 1:
+			*addr &= 0xff000000;
+			break;
+		case 2:
+			*addr &= 0xffff0000;
+			break;
+		case 3:
+			*addr &= 0xffffff00;
+			break;
+		}
+	}
+
+	/* Pass the packet up to the protocol layers. */
+	NetReceive (NetRxPackets[0], rxlen);
+
+	return rxlen;
+}
+
+/* Send a data block via Ethernet. */
+extern int eth_send (volatile void *packet, int length)
+{
+	int i, length32;
+	char *pa;
+	unsigned int *pa32, lastp = 0, rest;
+
+	pa = (char *) packet;
+	pa32 = (unsigned int *) packet;
+	length32 = length / 4;
+	rest = length % 4;
+
+	/* make sure there's no garbage in the last word */
+	switch (rest) {
+	case 0:
+		lastp = pa32[length32];
+		length32--;
+		break;
+	case 1:
+		lastp = pa32[length32] & 0x000000ff;
+		break;
+	case 2:
+		lastp = pa32[length32] & 0x0000ffff;
+		break;
+	case 3:
+		lastp = pa32[length32] & 0x00ffffff;
+		break;
+	}
+
+	/* write to the fifo */
+	for (i = 0; i < length32; i++)
+		SET_EADDR (NETARM_ETH_FIFO_DAT1, pa32[i]);
+
+	/* the last word is written to an extra register, this
+	   starts the transmission */
+	SET_EADDR (NETARM_ETH_FIFO_DAT2, lastp);
+
+	/* NETARM_ETH_TXSTAT_TXOK should be checked, to know if the transmission
+	   went fine. But we can't use the timer for a timeout loop because
+	   of it is used already in upper layers. So we just try some times. */
+	i = 0;
+	while (i < 50000) {
+		if ((GET_EADDR (NETARM_ETH_TX_STAT) & NETARM_ETH_TXSTAT_TXOK)
+		    == NETARM_ETH_TXSTAT_TXOK)
+			return 0;
+		i++;
+	}
+
+	printf ("eth_send timeout\n");
+	return 1;
+}
+
+#endif /* COMMANDS & CFG_NET */
+
+#endif /* CONFIG_DRIVER_NETARMETH */
diff --git a/drivers/net/netarm_eth.h b/drivers/net/netarm_eth.h
new file mode 100644
index 0000000..8edab82
--- /dev/null
+++ b/drivers/net/netarm_eth.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2003 IMMS gGmbH <www.imms.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * author(s): Thomas Elste, <info@elste.org>
+ */
+
+#include <asm/types.h>
+#include <config.h>
+
+#ifdef CONFIG_DRIVER_NETARMETH
+
+#define SET_EADDR(ad,val) *(volatile unsigned int*)(ad + NETARM_ETH_MODULE_BASE) = val
+#define GET_EADDR(ad) (*(volatile unsigned int*)(ad + NETARM_ETH_MODULE_BASE))
+
+#define NA_MII_POLL_BUSY_DELAY 900
+
+/* MII negotiation timeout value
+   500 jiffies = 5 seconds */
+#define NA_MII_NEGOTIATE_DELAY 30
+
+/* Registers in the physical layer chip */
+#define MII_PHY_CONTROL		0
+#define MII_PHY_STATUS		1
+#define MII_PHY_ID              2
+#define MII_PHY_AUTONEGADV	4
+
+#endif /* CONFIG_DRIVER_NETARMETH */
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
new file mode 100644
index 0000000..69089f9
--- /dev/null
+++ b/drivers/net/netconsole.c
@@ -0,0 +1,267 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_NETCONSOLE
+
+#include <command.h>
+#include <devices.h>
+#include <net.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char input_buffer[512];
+static int input_size = 0;		/* char count in input buffer */
+static int input_offset = 0;		/* offset to valid chars in input buffer */
+static int input_recursion = 0;
+static int output_recursion = 0;
+static int net_timeout;
+static uchar nc_ether[6];		/* server enet address */
+static IPaddr_t nc_ip;			/* server ip */
+static short nc_port;			/* source/target port */
+static const char *output_packet;	/* used by first send udp */
+static int output_packet_len = 0;
+
+static void nc_wait_arp_handler (uchar * pkt, unsigned dest, unsigned src,
+				 unsigned len)
+{
+	NetState = NETLOOP_SUCCESS;	/* got arp reply - quit net loop */
+}
+
+static void nc_handler (uchar * pkt, unsigned dest, unsigned src,
+			unsigned len)
+{
+	if (input_size)
+		NetState = NETLOOP_SUCCESS;	/* got input - quit net loop */
+}
+
+static void nc_timeout (void)
+{
+	NetState = NETLOOP_SUCCESS;
+}
+
+void NcStart (void)
+{
+	if (!output_packet_len || memcmp (nc_ether, NetEtherNullAddr, 6)) {
+		/* going to check for input packet */
+		NetSetHandler (nc_handler);
+		NetSetTimeout (net_timeout, nc_timeout);
+	} else {
+		/* send arp request */
+		uchar *pkt;
+		NetSetHandler (nc_wait_arp_handler);
+		pkt = (uchar *) NetTxPacket + NetEthHdrSize () + IP_HDR_SIZE;
+		memcpy (pkt, output_packet, output_packet_len);
+		NetSendUDPPacket (nc_ether, nc_ip, nc_port, nc_port, output_packet_len);
+	}
+}
+
+int nc_input_packet (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+	int end, chunk;
+
+	if (dest != nc_port || !len)
+		return 0;		/* not for us */
+
+	if (input_size == sizeof input_buffer)
+		return 1;		/* no space */
+	if (len > sizeof input_buffer - input_size)
+		len = sizeof input_buffer - input_size;
+
+	end = input_offset + input_size;
+	if (end > sizeof input_buffer)
+		end -= sizeof input_buffer;
+
+	chunk = len;
+	if (end + len > sizeof input_buffer) {
+		chunk = sizeof input_buffer - end;
+		memcpy(input_buffer, pkt + chunk, len - chunk);
+	}
+	memcpy (input_buffer + end, pkt, chunk);
+
+	input_size += len;
+
+	return 1;
+}
+
+static void nc_send_packet (const char *buf, int len)
+{
+	struct eth_device *eth;
+	int inited = 0;
+	uchar *pkt;
+	uchar *ether;
+	IPaddr_t ip;
+
+	if ((eth = eth_get_dev ()) == NULL) {
+		return;
+	}
+
+	if (!memcmp (nc_ether, NetEtherNullAddr, 6)) {
+		if (eth->state == ETH_STATE_ACTIVE)
+			return;	/* inside net loop */
+		output_packet = buf;
+		output_packet_len = len;
+		NetLoop (NETCONS);	/* wait for arp reply and send packet */
+		output_packet_len = 0;
+		return;
+	}
+
+	if (eth->state != ETH_STATE_ACTIVE) {
+		if (eth_init (gd->bd) < 0)
+			return;
+		inited = 1;
+	}
+	pkt = (uchar *) NetTxPacket + NetEthHdrSize () + IP_HDR_SIZE;
+	memcpy (pkt, buf, len);
+	ether = nc_ether;
+	ip = nc_ip;
+	NetSendUDPPacket (ether, ip, nc_port, nc_port, len);
+
+	if (inited)
+		eth_halt ();
+}
+
+int nc_start (void)
+{
+	int netmask, our_ip;
+
+	nc_port = 6666;		/* default port */
+
+	if (getenv ("ncip")) {
+		char *p;
+
+		nc_ip = getenv_IPaddr ("ncip");
+		if (!nc_ip)
+			return -1;	/* ncip is 0.0.0.0 */
+		if ((p = strchr (getenv ("ncip"), ':')) != NULL)
+			nc_port = simple_strtoul (p + 1, NULL, 10);
+	} else
+		nc_ip = ~0;		/* ncip is not set */
+
+	our_ip = getenv_IPaddr ("ipaddr");
+	netmask = getenv_IPaddr ("netmask");
+
+	if (nc_ip == ~0 ||				/* 255.255.255.255 */
+	    ((netmask & our_ip) == (netmask & nc_ip) &&	/* on the same net */
+	    (netmask | nc_ip) == ~0))			/* broadcast to our net */
+		memset (nc_ether, 0xff, sizeof nc_ether);
+	else
+		memset (nc_ether, 0, sizeof nc_ether);	/* force arp request */
+
+	return 0;
+}
+
+void nc_putc (char c)
+{
+	if (output_recursion)
+		return;
+	output_recursion = 1;
+
+	nc_send_packet (&c, 1);
+
+	output_recursion = 0;
+}
+
+void nc_puts (const char *s)
+{
+	int len;
+
+	if (output_recursion)
+		return;
+	output_recursion = 1;
+
+	if ((len = strlen (s)) > 512)
+		len = 512;
+
+	nc_send_packet (s, len);
+
+	output_recursion = 0;
+}
+
+int nc_getc (void)
+{
+	uchar c;
+
+	input_recursion = 1;
+
+	net_timeout = 0;	/* no timeout */
+	while (!input_size)
+		NetLoop (NETCONS);
+
+	input_recursion = 0;
+
+	c = input_buffer[input_offset++];
+
+	if (input_offset >= sizeof input_buffer)
+		input_offset -= sizeof input_buffer;
+	input_size--;
+
+	return c;
+}
+
+int nc_tstc (void)
+{
+	struct eth_device *eth;
+
+	if (input_recursion)
+		return 0;
+
+	if (input_size)
+		return 1;
+
+	eth = eth_get_dev ();
+	if (eth && eth->state == ETH_STATE_ACTIVE)
+		return 0;	/* inside net loop */
+
+	input_recursion = 1;
+
+	net_timeout = 1;
+	NetLoop (NETCONS);	/* kind of poll */
+
+	input_recursion = 0;
+
+	return input_size != 0;
+}
+
+int drv_nc_init (void)
+{
+	device_t dev;
+	int rc;
+
+	memset (&dev, 0, sizeof (dev));
+
+	strcpy (dev.name, "nc");
+	dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+	dev.start = nc_start;
+	dev.putc = nc_putc;
+	dev.puts = nc_puts;
+	dev.getc = nc_getc;
+	dev.tstc = nc_tstc;
+
+	rc = device_register (&dev);
+
+	return (rc == 0) ? 1 : rc;
+}
+
+#endif	/* CONFIG_NETCONSOLE */
diff --git a/drivers/net/nicext.h b/drivers/net/nicext.h
new file mode 100644
index 0000000..4074972
--- /dev/null
+++ b/drivers/net/nicext.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * Copyright(c) 2000-2001 Broadcom Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * Name:        nicext.h
+ *
+ * Description: Broadcom Network Interface Card Extension (NICE) is an
+ *              extension to Linux NET device kernel mode drivers.
+ *              NICE is designed to provide additional functionalities,
+ *              such as receive packet intercept. To support Broadcom NICE,
+ *              the network device driver can be modified by adding an
+ *              device ioctl handler and by indicating receiving packets
+ *              to the NICE receive handler. Broadcom NICE will only be
+ *              enabled by a NICE-aware intermediate driver, such as
+ *              Broadcom Advanced Server Program Driver (BASP). When NICE
+ *              is not enabled, the modified network device drivers
+ *              functions exactly as other non-NICE aware drivers.
+ *
+ * Author:      Frankie Fan
+ *
+ * Created:     September 17, 2000
+ *
+ ****************************************************************************/
+#ifndef _nicext_h_
+#define _nicext_h_
+
+/*
+ * ioctl for NICE
+ */
+#define SIOCNICE                   	SIOCDEVPRIVATE+7
+
+/*
+ * SIOCNICE:
+ *
+ * The following structure needs to be less than IFNAMSIZ (16 bytes) because
+ * we're overloading ifreq.ifr_ifru.
+ *
+ * If 16 bytes is not enough, we should consider relaxing this because
+ * this is no field after ifr_ifru in the ifreq structure. But we may
+ * run into future compatiability problem in case of changing struct ifreq.
+ */
+struct nice_req
+{
+    __u32 cmd;
+
+    union
+    {
+#ifdef __KERNEL__
+	/* cmd = NICE_CMD_SET_RX or NICE_CMD_GET_RX */
+	struct
+	{
+	    void (*nrqus1_rx)( struct sk_buff*, void* );
+	    void* nrqus1_ctx;
+	} nrqu_nrqus1;
+
+	/* cmd = NICE_CMD_QUERY_SUPPORT */
+	struct
+	{
+	    __u32 nrqus2_magic;
+	    __u32 nrqus2_support_rx:1;
+	    __u32 nrqus2_support_vlan:1;
+	    __u32 nrqus2_support_get_speed:1;
+	} nrqu_nrqus2;
+#endif
+
+	/* cmd = NICE_CMD_GET_SPEED */
+	struct
+	{
+	    unsigned int nrqus3_speed; /* 0 if link is down, */
+				       /* otherwise speed in Mbps */
+	} nrqu_nrqus3;
+
+	/* cmd = NICE_CMD_BLINK_LED */
+	struct
+	{
+	    unsigned int nrqus4_blink_time; /* blink duration in seconds */
+	} nrqu_nrqus4;
+
+    } nrq_nrqu;
+};
+
+#define nrq_rx           nrq_nrqu.nrqu_nrqus1.nrqus1_rx
+#define nrq_ctx          nrq_nrqu.nrqu_nrqus1.nrqus1_ctx
+#define nrq_support_rx   nrq_nrqu.nrqu_nrqus2.nrqus2_support_rx
+#define nrq_magic        nrq_nrqu.nrqu_nrqus2.nrqus2_magic
+#define nrq_support_vlan nrq_nrqu.nrqu_nrqus2.nrqus2_support_vlan
+#define nrq_support_get_speed nrq_nrqu.nrqu_nrqus2.nrqus2_support_get_speed
+#define nrq_speed        nrq_nrqu.nrqu_nrqus3.nrqus3_speed
+#define nrq_blink_time   nrq_nrqu.nrqu_nrqus4.nrqus4_blink_time
+
+/*
+ * magic constants
+ */
+#define NICE_REQUESTOR_MAGIC            0x4543494E /* NICE in ascii */
+#define NICE_DEVICE_MAGIC               0x4E494345 /* ECIN in ascii */
+
+/*
+ * command field
+ */
+#define NICE_CMD_QUERY_SUPPORT          0x00000001
+#define NICE_CMD_SET_RX                 0x00000002
+#define NICE_CMD_GET_RX                 0x00000003
+#define NICE_CMD_GET_SPEED              0x00000004
+#define NICE_CMD_BLINK_LED              0x00000005
+
+#endif  /* _nicext_h_ */
diff --git a/drivers/net/ns7520_eth.c b/drivers/net/ns7520_eth.c
new file mode 100644
index 0000000..a5a20df
--- /dev/null
+++ b/drivers/net/ns7520_eth.c
@@ -0,0 +1,859 @@
+/***********************************************************************
+ *
+ * Copyright (C) 2005 by Videon Central, Inc.
+ *
+ * $Id$
+ * @Author: Arthur Shipkowski
+ * @Descr: Ethernet driver for the NS7520. Uses polled Ethernet, like
+ *     the older netarmeth driver.  Note that attempting to filter
+ *     broadcast and multicast out in the SAFR register will cause
+ *     bad things due to released errata.
+ * @References: [1] NS7520 Hardware Reference, December 2003
+ *		[2] Intel LXT971 Datasheet #249414 Rev. 02
+ *
+ ***********************************************************************/
+
+#include <common.h>
+
+#if defined(CONFIG_DRIVER_NS7520_ETHERNET)
+
+#include <net.h>		/* NetSendPacket */
+#include <asm/arch/netarm_registers.h>
+#include <asm/arch/netarm_dma_module.h>
+
+#include "ns7520_eth.h"		/* for Ethernet and PHY */
+
+/**
+ * Send an error message to the terminal.
+ */
+#define ERROR(x) \
+do { \
+	char *__foo = strrchr(__FILE__, '/'); \
+	\
+	printf("%s: %d: %s(): ", (__foo == NULL ? __FILE__ : (__foo + 1)), \
+			__LINE__, __FUNCTION__); \
+	printf x; printf("\n"); \
+} while (0);
+
+/* some definition to make transistion to linux easier */
+
+#define NS7520_DRIVER_NAME	"eth"
+#define KERN_WARNING		"Warning:"
+#define KERN_ERR		"Error:"
+#define KERN_INFO		"Info:"
+
+#if 1
+# define DEBUG
+#endif
+
+#ifdef	DEBUG
+# define printk			printf
+
+# define DEBUG_INIT		0x0001
+# define DEBUG_MINOR		0x0002
+# define DEBUG_RX		0x0004
+# define DEBUG_TX		0x0008
+# define DEBUG_INT		0x0010
+# define DEBUG_POLL		0x0020
+# define DEBUG_LINK		0x0040
+# define DEBUG_MII		0x0100
+# define DEBUG_MII_LOW		0x0200
+# define DEBUG_MEM		0x0400
+# define DEBUG_ERROR		0x4000
+# define DEBUG_ERROR_CRIT	0x8000
+
+static int nDebugLvl = DEBUG_ERROR_CRIT;
+
+# define DEBUG_ARGS0( FLG, a0 ) if( ( nDebugLvl & (FLG) ) == (FLG) ) \
+		printf("%s: " a0, __FUNCTION__, 0, 0, 0, 0, 0, 0 )
+# define DEBUG_ARGS1( FLG, a0, a1 ) if( ( nDebugLvl & (FLG) ) == (FLG)) \
+		printf("%s: " a0, __FUNCTION__, (int)(a1), 0, 0, 0, 0, 0 )
+# define DEBUG_ARGS2( FLG, a0, a1, a2 ) if( (nDebugLvl & (FLG)) ==(FLG))\
+		printf("%s: " a0, __FUNCTION__, (int)(a1), (int)(a2), 0, 0,0,0 )
+# define DEBUG_ARGS3( FLG, a0, a1, a2, a3 ) if((nDebugLvl &(FLG))==(FLG))\
+		printf("%s: "a0,__FUNCTION__,(int)(a1),(int)(a2),(int)(a3),0,0,0)
+# define DEBUG_FN( FLG ) if( (nDebugLvl & (FLG)) == (FLG) ) \
+		printf("\r%s:line %d\n", (int)__FUNCTION__, __LINE__, 0,0,0,0);
+# define ASSERT( expr, func ) if( !( expr ) ) { \
+		printf( "Assertion failed! %s:line %d %s\n", \
+		(int)__FUNCTION__,__LINE__,(int)(#expr),0,0,0); \
+		func }
+#else				/* DEBUG */
+# define printk(...)
+# define DEBUG_ARGS0( FLG, a0 )
+# define DEBUG_ARGS1( FLG, a0, a1 )
+# define DEBUG_ARGS2( FLG, a0, a1, a2 )
+# define DEBUG_ARGS3( FLG, a0, a1, a2, a3 )
+# define DEBUG_FN( n )
+# define ASSERT(expr, func)
+#endif				/* DEBUG */
+
+#define NS7520_MII_NEG_DELAY		(5*CFG_HZ)	/* in s */
+#define TX_TIMEOUT			(5*CFG_HZ)	/* in s */
+#define RX_STALL_WORKAROUND_CNT 100
+
+static int ns7520_eth_reset(void);
+
+static void ns7520_link_auto_negotiate(void);
+static void ns7520_link_update_egcr(void);
+static void ns7520_link_print_changed(void);
+
+/* the PHY stuff */
+
+static char ns7520_mii_identify_phy(void);
+static unsigned short ns7520_mii_read(unsigned short uiRegister);
+static void ns7520_mii_write(unsigned short uiRegister,
+			     unsigned short uiData);
+static unsigned int ns7520_mii_get_clock_divisor(unsigned int
+						 unMaxMDIOClk);
+static unsigned int ns7520_mii_poll_busy(void);
+
+static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
+static unsigned int uiLastLinkStatus;
+static PhyType phyDetected = PHY_NONE;
+
+/***********************************************************************
+ * @Function: eth_init
+ * @Return: -1 on failure otherwise 0
+ * @Descr: Initializes the ethernet engine and uses either FS Forth's default
+ *	   MAC addr or the one in environment
+ ***********************************************************************/
+
+int eth_init(bd_t * pbis)
+{
+	unsigned char aucMACAddr[6];
+	char *pcTmp = getenv("ethaddr");
+	char *pcEnd;
+	int i;
+
+	DEBUG_FN(DEBUG_INIT);
+
+	/* no need to check for hardware */
+
+	if (!ns7520_eth_reset())
+		return -1;
+
+	if (NULL == pcTmp)
+		return -1;
+
+	for (i = 0; i < 6; i++) {
+		aucMACAddr[i] =
+		    pcTmp ? simple_strtoul(pcTmp, &pcEnd, 16) : 0;
+		pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
+	}
+
+	/* configure ethernet address */
+
+	*get_eth_reg_addr(NS7520_ETH_SA1) =
+	    aucMACAddr[5] << 8 | aucMACAddr[4];
+	*get_eth_reg_addr(NS7520_ETH_SA2) =
+	    aucMACAddr[3] << 8 | aucMACAddr[2];
+	*get_eth_reg_addr(NS7520_ETH_SA3) =
+	    aucMACAddr[1] << 8 | aucMACAddr[0];
+
+	/* enable hardware */
+
+	*get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;
+	*get_eth_reg_addr(NS7520_ETH_SUPP) = NS7520_ETH_SUPP_JABBER;
+	*get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;
+
+	/* the linux kernel may give packets < 60 bytes, for example arp */
+	*get_eth_reg_addr(NS7520_ETH_MAC2) = NS7520_ETH_MAC2_CRCEN |
+	    NS7520_ETH_MAC2_PADEN | NS7520_ETH_MAC2_HUGE;
+
+	/* Broadcast/multicast allowed; if you don't set this even unicast chokes */
+	/* Based on NS7520 errata documentation */
+	*get_eth_reg_addr(NS7520_ETH_SAFR) =
+	    NS7520_ETH_SAFR_BROAD | NS7520_ETH_SAFR_PRM;
+
+	/* enable receive and transmit FIFO, use 10/100 Mbps MII */
+	*get_eth_reg_addr(NS7520_ETH_EGCR) |=
+	    NS7520_ETH_EGCR_ETXWM_75 |
+	    NS7520_ETH_EGCR_ERX |
+	    NS7520_ETH_EGCR_ERXREG |
+	    NS7520_ETH_EGCR_ERXBR | NS7520_ETH_EGCR_ETX;
+
+	return 0;
+}
+
+/***********************************************************************
+ * @Function: eth_send
+ * @Return: -1 on timeout otherwise 1
+ * @Descr: sends one frame by DMA
+ ***********************************************************************/
+
+int eth_send(volatile void *pPacket, int nLen)
+{
+	int i, length32, retval = 1;
+	char *pa;
+	unsigned int *pa32, lastp = 0, rest;
+	unsigned int status;
+
+	pa = (char *) pPacket;
+	pa32 = (unsigned int *) pPacket;
+	length32 = nLen / 4;
+	rest = nLen % 4;
+
+	/* make sure there's no garbage in the last word */
+	switch (rest) {
+	case 0:
+		lastp = pa32[length32 - 1];
+		length32--;
+		break;
+	case 1:
+		lastp = pa32[length32] & 0x000000ff;
+		break;
+	case 2:
+		lastp = pa32[length32] & 0x0000ffff;
+		break;
+	case 3:
+		lastp = pa32[length32] & 0x00ffffff;
+		break;
+	}
+
+	while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
+		NS7520_ETH_EGSR_TXREGE)
+	       == 0) {
+	}
+
+	/* write to the fifo */
+	for (i = 0; i < length32; i++)
+		*get_eth_reg_addr(NS7520_ETH_FIFO) = pa32[i];
+
+	/* the last word is written to an extra register, this
+	   starts the transmission */
+	*get_eth_reg_addr(NS7520_ETH_FIFOL) = lastp;
+
+	/* Wait for it to be done */
+	while ((*get_eth_reg_addr(NS7520_ETH_EGSR) & NS7520_ETH_EGSR_TXBC)
+	       == 0) {
+	}
+	status = (*get_eth_reg_addr(NS7520_ETH_ETSR));
+	*get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_TXBC;	/* Clear it now */
+
+	if (status & NS7520_ETH_ETSR_TXOK) {
+		retval = 0;	/* We're OK! */
+	} else if (status & NS7520_ETH_ETSR_TXDEF) {
+		printf("Deferred, we'll see.\n");
+		retval = 0;
+	} else if (status & NS7520_ETH_ETSR_TXAL) {
+		printf("Late collision error, %d collisions.\n",
+		       (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
+		       NS7520_ETH_ETSR_TXCOLC);
+	} else if (status & NS7520_ETH_ETSR_TXAEC) {
+		printf("Excessive collisions: %d\n",
+		       (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
+		       NS7520_ETH_ETSR_TXCOLC);
+	} else if (status & NS7520_ETH_ETSR_TXAED) {
+		printf("Excessive deferral on xmit.\n");
+	} else if (status & NS7520_ETH_ETSR_TXAUR) {
+		printf("Packet underrun.\n");
+	} else if (status & NS7520_ETH_ETSR_TXAJ) {
+		printf("Jumbo packet error.\n");
+	} else {
+		printf("Error: Should never get here.\n");
+	}
+
+	return (retval);
+}
+
+/***********************************************************************
+ * @Function: eth_rx
+ * @Return: size of last frame in bytes or 0 if no frame available
+ * @Descr: gives one frame to U-Boot which has been copied by DMA engine already
+ *	   to NetRxPackets[ 0 ].
+ ***********************************************************************/
+
+int eth_rx(void)
+{
+	int i;
+	unsigned short rxlen;
+	unsigned short totrxlen = 0;
+	unsigned int *addr;
+	unsigned int rxstatus, lastrxlen;
+	char *pa;
+
+	/* If RXBR is 1, data block was received */
+	while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
+		NS7520_ETH_EGSR_RXBR) == NS7520_ETH_EGSR_RXBR) {
+
+		/* get status register and the length of received block */
+		rxstatus = *get_eth_reg_addr(NS7520_ETH_ERSR);
+		rxlen = (rxstatus & NS7520_ETH_ERSR_RXSIZE) >> 16;
+
+		/* clear RXBR to make fifo available */
+		*get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_RXBR;
+
+		if (rxstatus & NS7520_ETH_ERSR_ROVER) {
+			printf("Receive overrun, resetting FIFO.\n");
+			*get_eth_reg_addr(NS7520_ETH_EGCR) &=
+			    ~NS7520_ETH_EGCR_ERX;
+			udelay(20);
+			*get_eth_reg_addr(NS7520_ETH_EGCR) |=
+			    NS7520_ETH_EGCR_ERX;
+		}
+		if (rxlen == 0) {
+			printf("Nothing.\n");
+			return 0;
+		}
+
+		addr = (unsigned int *) NetRxPackets[0];
+		pa = (char *) NetRxPackets[0];
+
+		/* read the fifo */
+		for (i = 0; i < rxlen / 4; i++) {
+			*addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
+			addr++;
+		}
+
+		if ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
+		    NS7520_ETH_EGSR_RXREGR) {
+			/* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */
+			lastrxlen =
+			    ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
+			     NS7520_ETH_EGSR_RXFDB_MA) >> 28;
+			*addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
+			switch (lastrxlen) {
+			case 1:
+				*addr &= 0xff000000;
+				break;
+			case 2:
+				*addr &= 0xffff0000;
+				break;
+			case 3:
+				*addr &= 0xffffff00;
+				break;
+			}
+		}
+
+		/* Pass the packet up to the protocol layers. */
+		NetReceive(NetRxPackets[0], rxlen - 4);
+		totrxlen += rxlen - 4;
+	}
+
+	return totrxlen;
+}
+
+/***********************************************************************
+ * @Function: eth_halt
+ * @Return: n/a
+ * @Descr: stops the ethernet engine
+ ***********************************************************************/
+
+void eth_halt(void)
+{
+	DEBUG_FN(DEBUG_INIT);
+
+	*get_eth_reg_addr(NS7520_ETH_MAC1) &= ~NS7520_ETH_MAC1_RXEN;
+	*get_eth_reg_addr(NS7520_ETH_EGCR) &= ~(NS7520_ETH_EGCR_ERX |
+						NS7520_ETH_EGCR_ERXDMA |
+						NS7520_ETH_EGCR_ERXREG |
+						NS7520_ETH_EGCR_ERXBR |
+						NS7520_ETH_EGCR_ETX |
+						NS7520_ETH_EGCR_ETXDMA);
+}
+
+/***********************************************************************
+ * @Function: ns7520_eth_reset
+ * @Return: 0 on failure otherwise 1
+ * @Descr: resets the ethernet interface and the PHY,
+ *	   performs auto negotiation or fixed modes
+ ***********************************************************************/
+
+static int ns7520_eth_reset(void)
+{
+	DEBUG_FN(DEBUG_MINOR);
+
+	/* Reset important registers */
+	*get_eth_reg_addr(NS7520_ETH_EGCR) = 0;	/* Null it out! */
+	*get_eth_reg_addr(NS7520_ETH_MAC1) &= NS7520_ETH_MAC1_SRST;
+	*get_eth_reg_addr(NS7520_ETH_MAC2) = 0;
+	/* Reset MAC */
+	*get_eth_reg_addr(NS7520_ETH_EGCR) |= NS7520_ETH_EGCR_MAC_RES;
+	udelay(5);
+	*get_eth_reg_addr(NS7520_ETH_EGCR) &= ~NS7520_ETH_EGCR_MAC_RES;
+
+	/* reset and initialize PHY */
+
+	*get_eth_reg_addr(NS7520_ETH_MAC1) &= ~NS7520_ETH_MAC1_SRST;
+
+	/* we don't support hot plugging of PHY, therefore we don't reset
+	   phyDetected and nPhyMaxMdioClock here. The risk is if the setting is
+	   incorrect the first open
+	   may detect the PHY correctly but succeding will fail
+	   For reseting the PHY and identifying we have to use the standard
+	   MDIO CLOCK value 2.5 MHz only after hardware reset
+	   After having identified the PHY we will do faster */
+
+	*get_eth_reg_addr(NS7520_ETH_MCFG) =
+	    ns7520_mii_get_clock_divisor(nPhyMaxMdioClock);
+
+	/* reset PHY */
+	ns7520_mii_write(PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);
+	ns7520_mii_write(PHY_COMMON_CTRL, 0);
+
+	udelay(3000);		/* [2] p.70 says at least 300us reset recovery time. */
+
+	/* MII clock has been setup to default, ns7520_mii_identify_phy should
+	   work for all */
+
+	if (!ns7520_mii_identify_phy()) {
+		printk(KERN_ERR NS7520_DRIVER_NAME
+		       ": Unsupported PHY, aborting\n");
+		return 0;
+	}
+
+	/* now take the highest MDIO clock possible after detection */
+	*get_eth_reg_addr(NS7520_ETH_MCFG) =
+	    ns7520_mii_get_clock_divisor(nPhyMaxMdioClock);
+
+	/* PHY has been detected, so there can be no abort reason and we can
+	   finish initializing ethernet */
+
+	uiLastLinkStatus = 0xff;	/* undefined */
+
+	ns7520_link_auto_negotiate();
+
+	if (phyDetected == PHY_LXT971A)
+		/* set LED2 to link mode */
+		ns7520_mii_write(PHY_LXT971_LED_CFG,
+				 (PHY_LXT971_LED_CFG_LINK_ACT <<
+				  PHY_LXT971_LED_CFG_SHIFT_LED2) |
+				 (PHY_LXT971_LED_CFG_TRANSMIT <<
+				  PHY_LXT971_LED_CFG_SHIFT_LED1));
+
+	return 1;
+}
+
+/***********************************************************************
+ * @Function: ns7520_link_auto_negotiate
+ * @Return: void
+ * @Descr: performs auto-negotation of link.
+ ***********************************************************************/
+
+static void ns7520_link_auto_negotiate(void)
+{
+	unsigned long ulStartJiffies;
+	unsigned short uiStatus;
+
+	DEBUG_FN(DEBUG_LINK);
+
+	/* run auto-negotation */
+	/* define what we are capable of */
+	ns7520_mii_write(PHY_COMMON_AUTO_ADV,
+			 PHY_COMMON_AUTO_ADV_100BTXFD |
+			 PHY_COMMON_AUTO_ADV_100BTX |
+			 PHY_COMMON_AUTO_ADV_10BTFD |
+			 PHY_COMMON_AUTO_ADV_10BT |
+			 PHY_COMMON_AUTO_ADV_802_3);
+	/* start auto-negotiation */
+	ns7520_mii_write(PHY_COMMON_CTRL,
+			 PHY_COMMON_CTRL_AUTO_NEG |
+			 PHY_COMMON_CTRL_RES_AUTO);
+
+	/* wait for completion */
+
+	ulStartJiffies = get_timer(0);
+	while (get_timer(0) < ulStartJiffies + NS7520_MII_NEG_DELAY) {
+		uiStatus = ns7520_mii_read(PHY_COMMON_STAT);
+		if ((uiStatus &
+		     (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT))
+		    ==
+		    (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) {
+			/* lucky we are, auto-negotiation succeeded */
+			ns7520_link_print_changed();
+			ns7520_link_update_egcr();
+			return;
+		}
+	}
+
+	DEBUG_ARGS0(DEBUG_LINK, "auto-negotiation timed out\n");
+	/* ignore invalid link settings */
+}
+
+/***********************************************************************
+ * @Function: ns7520_link_update_egcr
+ * @Return: void
+ * @Descr: updates the EGCR and MAC2 link status after mode change or
+ *	   auto-negotation
+ ***********************************************************************/
+
+static void ns7520_link_update_egcr(void)
+{
+	unsigned int unEGCR;
+	unsigned int unMAC2;
+	unsigned int unIPGT;
+
+	DEBUG_FN(DEBUG_LINK);
+
+	unEGCR = *get_eth_reg_addr(NS7520_ETH_EGCR);
+	unMAC2 = *get_eth_reg_addr(NS7520_ETH_MAC2);
+	unIPGT =
+	    *get_eth_reg_addr(NS7520_ETH_IPGT) & ~NS7520_ETH_IPGT_IPGT;
+
+	unEGCR &= ~NS7520_ETH_EGCR_EFULLD;
+	unMAC2 &= ~NS7520_ETH_MAC2_FULLD;
+	if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)
+	    == PHY_LXT971_STAT2_DUPLEX_MODE) {
+		unEGCR |= NS7520_ETH_EGCR_EFULLD;
+		unMAC2 |= NS7520_ETH_MAC2_FULLD;
+		unIPGT |= 0x15;	/* see [1] p. 167 */
+	} else
+		unIPGT |= 0x12;	/* see [1] p. 167 */
+
+	*get_eth_reg_addr(NS7520_ETH_MAC2) = unMAC2;
+	*get_eth_reg_addr(NS7520_ETH_EGCR) = unEGCR;
+	*get_eth_reg_addr(NS7520_ETH_IPGT) = unIPGT;
+}
+
+/***********************************************************************
+ * @Function: ns7520_link_print_changed
+ * @Return: void
+ * @Descr: checks whether the link status has changed and if so prints
+ *	   the new mode
+ ***********************************************************************/
+
+static void ns7520_link_print_changed(void)
+{
+	unsigned short uiStatus;
+	unsigned short uiControl;
+
+	DEBUG_FN(DEBUG_LINK);
+
+	uiControl = ns7520_mii_read(PHY_COMMON_CTRL);
+
+	if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) ==
+	    PHY_COMMON_CTRL_AUTO_NEG) {
+		/* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */
+		uiStatus = ns7520_mii_read(PHY_COMMON_STAT);
+
+		if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) {
+			printk(KERN_WARNING NS7520_DRIVER_NAME
+			       ": link down\n");
+			/* @TODO Linux: carrier_off */
+		} else {
+			/* @TODO Linux: carrier_on */
+			if (phyDetected == PHY_LXT971A) {
+				uiStatus =
+				    ns7520_mii_read(PHY_LXT971_STAT2);
+				uiStatus &=
+				    (PHY_LXT971_STAT2_100BTX |
+				     PHY_LXT971_STAT2_DUPLEX_MODE |
+				     PHY_LXT971_STAT2_AUTO_NEG);
+
+				/* mask out all uninteresting parts */
+			}
+			/* other PHYs must store there link information in
+			   uiStatus as PHY_LXT971 */
+		}
+	} else {
+		/* mode has been forced, so uiStatus should be the same as the
+		   last link status, enforce printing */
+		uiStatus = uiLastLinkStatus;
+		uiLastLinkStatus = 0xff;
+	}
+
+	if (uiStatus != uiLastLinkStatus) {
+		/* save current link status */
+		uiLastLinkStatus = uiStatus;
+
+		/* print new link status */
+
+		printk(KERN_INFO NS7520_DRIVER_NAME
+		       ": link mode %i Mbps %s duplex %s\n",
+		       (uiStatus & PHY_LXT971_STAT2_100BTX) ? 100 : 10,
+		       (uiStatus & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" :
+		       "half",
+		       (uiStatus & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" :
+		       "");
+	}
+}
+
+/***********************************************************************
+ * the MII low level stuff
+ ***********************************************************************/
+
+/***********************************************************************
+ * @Function: ns7520_mii_identify_phy
+ * @Return: 1 if supported PHY has been detected otherwise 0
+ * @Descr: checks for supported PHY and prints the IDs.
+ ***********************************************************************/
+
+static char ns7520_mii_identify_phy(void)
+{
+	unsigned short uiID1;
+	unsigned short uiID2;
+	unsigned char *szName;
+	char cRes = 0;
+
+	DEBUG_FN(DEBUG_MII);
+
+	phyDetected = (PhyType) uiID1 = ns7520_mii_read(PHY_COMMON_ID1);
+
+	switch (phyDetected) {
+	case PHY_LXT971A:
+		szName = "LXT971A";
+		uiID2 = ns7520_mii_read(PHY_COMMON_ID2);
+		nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK;
+		cRes = 1;
+		break;
+	case PHY_NONE:
+	default:
+		/* in case uiID1 == 0 && uiID2 == 0 we may have the wrong
+		   address or reset sets the wrong NS7520_ETH_MCFG_CLKS */
+
+		uiID2 = 0;
+		szName = "unknown";
+		nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
+		phyDetected = PHY_NONE;
+	}
+
+	printk(KERN_INFO NS7520_DRIVER_NAME
+	       ": PHY (0x%x, 0x%x) = %s detected\n", uiID1, uiID2, szName);
+
+	return cRes;
+}
+
+/***********************************************************************
+ * @Function: ns7520_mii_read
+ * @Return: the data read from PHY register uiRegister
+ * @Descr: the data read may be invalid if timed out. If so, a message
+ *	   is printed but the invalid data is returned.
+ *	   The fixed device address is being used.
+ ***********************************************************************/
+
+static unsigned short ns7520_mii_read(unsigned short uiRegister)
+{
+	DEBUG_FN(DEBUG_MII_LOW);
+
+	/* write MII register to be read */
+	*get_eth_reg_addr(NS7520_ETH_MADR) =
+	    CONFIG_PHY_ADDR << 8 | uiRegister;
+
+	*get_eth_reg_addr(NS7520_ETH_MCMD) = NS7520_ETH_MCMD_READ;
+
+	if (!ns7520_mii_poll_busy())
+		printk(KERN_WARNING NS7520_DRIVER_NAME
+		       ": MII still busy in read\n");
+	/* continue to read */
+
+	*get_eth_reg_addr(NS7520_ETH_MCMD) = 0;
+
+	return (unsigned short) (*get_eth_reg_addr(NS7520_ETH_MRDD));
+}
+
+/***********************************************************************
+ * @Function: ns7520_mii_write
+ * @Return: nothing
+ * @Descr: writes the data to the PHY register. In case of a timeout,
+ *	   no special handling is performed but a message printed
+ *	   The fixed device address is being used.
+ ***********************************************************************/
+
+static void ns7520_mii_write(unsigned short uiRegister,
+			     unsigned short uiData)
+{
+	DEBUG_FN(DEBUG_MII_LOW);
+
+	/* write MII register to be written */
+	*get_eth_reg_addr(NS7520_ETH_MADR) =
+	    CONFIG_PHY_ADDR << 8 | uiRegister;
+
+	*get_eth_reg_addr(NS7520_ETH_MWTD) = uiData;
+
+	if (!ns7520_mii_poll_busy()) {
+		printf(KERN_WARNING NS7520_DRIVER_NAME
+		       ": MII still busy in write\n");
+	}
+}
+
+/***********************************************************************
+ * @Function: ns7520_mii_get_clock_divisor
+ * @Return: the clock divisor that should be used in NS7520_ETH_MCFG_CLKS
+ * @Descr: if no clock divisor can be calculated for the
+ *	   current SYSCLK and the maximum MDIO Clock, a warning is printed
+ *	   and the greatest divisor is taken
+ ***********************************************************************/
+
+static unsigned int ns7520_mii_get_clock_divisor(unsigned int unMaxMDIOClk)
+{
+	struct {
+		unsigned int unSysClkDivisor;
+		unsigned int unClks;	/* field for NS7520_ETH_MCFG_CLKS */
+	} PHYClockDivisors[] = {
+		{
+		4, NS7520_ETH_MCFG_CLKS_4}, {
+		6, NS7520_ETH_MCFG_CLKS_6}, {
+		8, NS7520_ETH_MCFG_CLKS_8}, {
+		10, NS7520_ETH_MCFG_CLKS_10}, {
+		14, NS7520_ETH_MCFG_CLKS_14}, {
+		20, NS7520_ETH_MCFG_CLKS_20}, {
+		28, NS7520_ETH_MCFG_CLKS_28}
+	};
+
+	int nIndexSysClkDiv;
+	int nArraySize =
+	    sizeof(PHYClockDivisors) / sizeof(PHYClockDivisors[0]);
+	unsigned int unClks = NS7520_ETH_MCFG_CLKS_28;	/* defaults to
+							   greatest div */
+
+	DEBUG_FN(DEBUG_INIT);
+
+	for (nIndexSysClkDiv = 0; nIndexSysClkDiv < nArraySize;
+	     nIndexSysClkDiv++) {
+		/* find first sysclock divisor that isn't higher than 2.5 MHz
+		   clock */
+		if (NETARM_XTAL_FREQ /
+		    PHYClockDivisors[nIndexSysClkDiv].unSysClkDivisor <=
+		    unMaxMDIOClk) {
+			unClks = PHYClockDivisors[nIndexSysClkDiv].unClks;
+			break;
+		}
+	}
+
+	DEBUG_ARGS2(DEBUG_INIT,
+		    "Taking MDIO Clock bit mask 0x%0x for max clock %i\n",
+		    unClks, unMaxMDIOClk);
+
+	/* return greatest divisor */
+	return unClks;
+}
+
+/***********************************************************************
+ * @Function: ns7520_mii_poll_busy
+ * @Return: 0 if timed out otherwise the remaing timeout
+ * @Descr: waits until the MII has completed a command or it times out
+ *	   code may be interrupted by hard interrupts.
+ *	   It is not checked what happens on multiple actions when
+ *	   the first is still being busy and we timeout.
+ ***********************************************************************/
+
+static unsigned int ns7520_mii_poll_busy(void)
+{
+	unsigned int unTimeout = 1000;
+
+	DEBUG_FN(DEBUG_MII_LOW);
+
+	while (((*get_eth_reg_addr(NS7520_ETH_MIND) & NS7520_ETH_MIND_BUSY)
+		== NS7520_ETH_MIND_BUSY) && unTimeout)
+		unTimeout--;
+
+	return unTimeout;
+}
+
+/* ----------------------------------------------------------------------------
+ * Net+ARM ethernet MII functionality.
+ */
+#if defined(CONFIG_MII)
+
+/**
+ * Maximum MII address we support
+ */
+#define MII_ADDRESS_MAX			(31)
+
+/**
+ * Maximum MII register address we support
+ */
+#define MII_REGISTER_MAX		(31)
+
+/**
+ * Ethernet MII interface return values for public functions.
+ */
+enum mii_status {
+	MII_STATUS_SUCCESS = 0,
+	MII_STATUS_FAILURE = 1,
+};
+
+/**
+ * Read a 16-bit value from an MII register.
+ */
+extern int ns7520_miiphy_read(char *devname, unsigned char const addr,
+		unsigned char const reg, unsigned short *const value)
+{
+	int ret = MII_STATUS_FAILURE;
+
+	/* Parameter checks */
+	if (addr > MII_ADDRESS_MAX) {
+		ERROR(("invalid addr, 0x%02X", addr));
+		goto miiphy_read_failed_0;
+	}
+
+	if (reg > MII_REGISTER_MAX) {
+		ERROR(("invalid reg, 0x%02X", reg));
+		goto miiphy_read_failed_0;
+	}
+
+	if (value == NULL) {
+		ERROR(("NULL value"));
+		goto miiphy_read_failed_0;
+	}
+
+	DEBUG_FN(DEBUG_MII_LOW);
+
+	/* write MII register to be read */
+	*get_eth_reg_addr(NS7520_ETH_MADR) = (addr << 8) | reg;
+
+	*get_eth_reg_addr(NS7520_ETH_MCMD) = NS7520_ETH_MCMD_READ;
+
+	if (!ns7520_mii_poll_busy())
+		printk(KERN_WARNING NS7520_DRIVER_NAME
+		       ": MII still busy in read\n");
+	/* continue to read */
+
+	*get_eth_reg_addr(NS7520_ETH_MCMD) = 0;
+
+	*value = (*get_eth_reg_addr(NS7520_ETH_MRDD));
+	ret = MII_STATUS_SUCCESS;
+	/* Fall through */
+
+      miiphy_read_failed_0:
+	return (ret);
+}
+
+/**
+ * Write a 16-bit value to an MII register.
+ */
+extern int ns7520_miiphy_write(char *devname, unsigned char const addr,
+		unsigned char const reg, unsigned short const value)
+{
+	int ret = MII_STATUS_FAILURE;
+
+	/* Parameter checks */
+	if (addr > MII_ADDRESS_MAX) {
+		ERROR(("invalid addr, 0x%02X", addr));
+		goto miiphy_write_failed_0;
+	}
+
+	if (reg > MII_REGISTER_MAX) {
+		ERROR(("invalid reg, 0x%02X", reg));
+		goto miiphy_write_failed_0;
+	}
+
+	/* write MII register to be written */
+	*get_eth_reg_addr(NS7520_ETH_MADR) = (addr << 8) | reg;
+
+	*get_eth_reg_addr(NS7520_ETH_MWTD) = value;
+
+	if (!ns7520_mii_poll_busy()) {
+		printf(KERN_WARNING NS7520_DRIVER_NAME
+		       ": MII still busy in write\n");
+	}
+
+	ret = MII_STATUS_SUCCESS;
+	/* Fall through */
+
+      miiphy_write_failed_0:
+	return (ret);
+}
+#endif				/* defined(CONFIG_MII) */
+#endif				/* CONFIG_DRIVER_NS7520_ETHERNET */
+
+int ns7520_miiphy_initialize(bd_t *bis)
+{
+#if defined(CONFIG_DRIVER_NS7520_ETHERNET)
+#if defined(CONFIG_MII)
+	miiphy_register("ns7520phy", ns7520_miiphy_read, ns7520_miiphy_write);
+#endif
+#endif
+	return 0;
+}
diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c
new file mode 100644
index 0000000..f8b143a
--- /dev/null
+++ b/drivers/net/ns8382x.c
@@ -0,0 +1,863 @@
+/*
+   ns8382x.c: A U-Boot driver for the NatSemi DP8382[01].
+   ported by: Mark A. Rakes (mark_rakes@vivato.net)
+
+   Adapted from:
+   1. an Etherboot driver for DP8381[56] written by:
+	   Copyright (C) 2001 Entity Cyber, Inc.
+
+	   This development of this Etherboot driver was funded by
+		  Sicom Systems: http://www.sicompos.com/
+
+	   Author: Marty Connor (mdc@thinguin.org)
+	   Adapted from a Linux driver which was written by Donald Becker
+
+	   This software may be used and distributed according to the terms
+	   of the GNU Public License (GPL), incorporated herein by reference.
+
+   2. A Linux driver by Donald Becker, ns820.c:
+		Written/copyright 1999-2002 by Donald Becker.
+
+		This software may be used and distributed according to the terms of
+		the GNU General Public License (GPL), incorporated herein by reference.
+		Drivers based on or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.  This file is not
+		a complete program and may only be used when the entire operating
+		system is licensed under the GPL.  License for under other terms may be
+		available.  Contact the original author for details.
+
+		The original author may be reached as becker@scyld.com, or at
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
+		Support information and updates available at
+		http://www.scyld.com/network/netsemi.html
+
+   Datasheets available from:
+   http://www.national.com/pf/DP/DP83820.html
+   http://www.national.com/pf/DP/DP83821.html
+*/
+
+/* Revision History
+ * October 2002 mar	1.0
+ *   Initial U-Boot Release.
+ *   	Tested with Netgear GA622T (83820)
+ *   	and SMC9452TX (83821)
+ *   	NOTE: custom boards with these chips may (likely) require
+ *   	a programmed EEPROM device (if present) in order to work
+ *   	correctly.
+*/
+
+/* Includes */
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_NS8382X)
+
+/* defines */
+#define DSIZE     0x00000FFF
+#define ETH_ALEN		6
+#define CRC_SIZE  4
+#define TOUT_LOOP   500000
+#define TX_BUF_SIZE    1536
+#define RX_BUF_SIZE    1536
+#define NUM_RX_DESC    4	/* Number of Rx descriptor registers. */
+
+enum register_offsets {
+	ChipCmd = 0x00,
+	ChipConfig = 0x04,
+	EECtrl = 0x08,
+	IntrMask = 0x14,
+	IntrEnable = 0x18,
+	TxRingPtr = 0x20,
+	TxRingPtrHi = 0x24,
+	TxConfig = 0x28,
+	RxRingPtr = 0x30,
+	RxRingPtrHi = 0x34,
+	RxConfig = 0x38,
+	PriQueue = 0x3C,
+	RxFilterAddr = 0x48,
+	RxFilterData = 0x4C,
+	ClkRun = 0xCC,
+	PCIPM = 0x44,
+};
+
+enum ChipCmdBits {
+	ChipReset = 0x100,
+	RxReset = 0x20,
+	TxReset = 0x10,
+	RxOff = 0x08,
+	RxOn = 0x04,
+	TxOff = 0x02,
+	TxOn = 0x01
+};
+
+enum ChipConfigBits {
+	LinkSts = 0x80000000,
+	GigSpeed = 0x40000000,
+	HundSpeed = 0x20000000,
+	FullDuplex = 0x10000000,
+	TBIEn = 0x01000000,
+	Mode1000 = 0x00400000,
+	T64En = 0x00004000,
+	D64En = 0x00001000,
+	M64En = 0x00000800,
+	PhyRst = 0x00000400,
+	PhyDis = 0x00000200,
+	ExtStEn = 0x00000100,
+	BEMode = 0x00000001,
+};
+#define SpeedStatus_Polarity ( GigSpeed | HundSpeed | FullDuplex)
+
+enum TxConfig_bits {
+	TxDrthMask 	= 0x000000ff,
+	TxFlthMask 	= 0x0000ff00,
+	TxMxdmaMask	= 0x00700000,
+	TxMxdma_8 	= 0x00100000,
+	TxMxdma_16 	= 0x00200000,
+	TxMxdma_32 	= 0x00300000,
+	TxMxdma_64 	= 0x00400000,
+	TxMxdma_128 	= 0x00500000,
+	TxMxdma_256 	= 0x00600000,
+	TxMxdma_512 	= 0x00700000,
+	TxMxdma_1024 	= 0x00000000,
+	TxCollRetry 	= 0x00800000,
+	TxAutoPad 	= 0x10000000,
+	TxMacLoop 	= 0x20000000,
+	TxHeartIgn 	= 0x40000000,
+	TxCarrierIgn 	= 0x80000000
+};
+
+enum RxConfig_bits {
+	RxDrthMask 	= 0x0000003e,
+	RxMxdmaMask 	= 0x00700000,
+	RxMxdma_8 	= 0x00100000,
+	RxMxdma_16 	= 0x00200000,
+	RxMxdma_32 	= 0x00300000,
+	RxMxdma_64 	= 0x00400000,
+	RxMxdma_128 	= 0x00500000,
+	RxMxdma_256 	= 0x00600000,
+	RxMxdma_512 	= 0x00700000,
+	RxMxdma_1024 	= 0x00000000,
+	RxAcceptLenErr 	= 0x04000000,
+	RxAcceptLong 	= 0x08000000,
+	RxAcceptTx 	= 0x10000000,
+	RxStripCRC 	= 0x20000000,
+	RxAcceptRunt 	= 0x40000000,
+	RxAcceptErr 	= 0x80000000,
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+	RxFilterEnable 		= 0x80000000,
+	AcceptAllBroadcast 	= 0x40000000,
+	AcceptAllMulticast 	= 0x20000000,
+	AcceptAllUnicast 	= 0x10000000,
+	AcceptPerfectMatch 	= 0x08000000,
+};
+
+typedef struct _BufferDesc {
+	u32 link;
+	u32 bufptr;
+	vu_long cmdsts;
+	u32 extsts;		/*not used here */
+} BufferDesc;
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+	DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000,
+	DescNoCRC = 0x10000000, DescPktOK = 0x08000000,
+	DescSizeMask = 0xfff,
+
+	DescTxAbort = 0x04000000, DescTxFIFO = 0x02000000,
+	DescTxCarrier = 0x01000000, DescTxDefer = 0x00800000,
+	DescTxExcDefer = 0x00400000, DescTxOOWCol = 0x00200000,
+	DescTxExcColl = 0x00100000, DescTxCollCount = 0x000f0000,
+
+	DescRxAbort = 0x04000000, DescRxOver = 0x02000000,
+	DescRxDest = 0x01800000, DescRxLong = 0x00400000,
+	DescRxRunt = 0x00200000, DescRxInvalid = 0x00100000,
+	DescRxCRC = 0x00080000, DescRxAlign = 0x00040000,
+	DescRxLoop = 0x00020000, DesRxColl = 0x00010000,
+};
+
+/* Bits in MEAR */
+enum mii_reg_bits {
+	MDIO_ShiftClk = 0x0040,
+	MDIO_EnbOutput = 0x0020,
+	MDIO_Data = 0x0010,
+};
+
+/* PHY Register offsets.  */
+enum phy_reg_offsets {
+	BMCR = 0x00,
+	BMSR = 0x01,
+	PHYIDR1 = 0x02,
+	PHYIDR2 = 0x03,
+	ANAR = 0x04,
+	KTCR = 0x09,
+};
+
+/* basic mode control register bits */
+enum bmcr_bits {
+	Bmcr_Reset = 0x8000,
+	Bmcr_Loop = 0x4000,
+	Bmcr_Speed0 = 0x2000,
+	Bmcr_AutoNegEn = 0x1000,	/*if set ignores Duplex, Speed[01] */
+	Bmcr_RstAutoNeg = 0x0200,
+	Bmcr_Duplex = 0x0100,
+	Bmcr_Speed1 = 0x0040,
+	Bmcr_Force10H = 0x0000,
+	Bmcr_Force10F = 0x0100,
+	Bmcr_Force100H = 0x2000,
+	Bmcr_Force100F = 0x2100,
+	Bmcr_Force1000H = 0x0040,
+	Bmcr_Force1000F = 0x0140,
+};
+
+/* auto negotiation advertisement register */
+enum anar_bits {
+	anar_adv_100F = 0x0100,
+	anar_adv_100H = 0x0080,
+	anar_adv_10F = 0x0040,
+	anar_adv_10H = 0x0020,
+	anar_ieee_8023 = 0x0001,
+};
+
+/* 1K-base T control register */
+enum ktcr_bits {
+	ktcr_adv_1000H = 0x0100,
+	ktcr_adv_1000F = 0x0200,
+};
+
+/* Globals */
+static u32 SavedClkRun;
+static unsigned int cur_rx;
+static unsigned int rx_config;
+static unsigned int tx_config;
+
+/* Note: transmit and receive buffers and descriptors must be
+   long long word aligned */
+static BufferDesc txd __attribute__ ((aligned(8)));
+static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(8)));
+static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(8)));
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]
+    __attribute__ ((aligned(8)));
+
+/* Function Prototypes */
+static int mdio_read(struct eth_device *dev, int phy_id, int addr);
+static void mdio_write(struct eth_device *dev, int phy_id, int addr, int value);
+static void mdio_sync(struct eth_device *dev, u32 offset);
+static int ns8382x_init(struct eth_device *dev, bd_t * bis);
+static void ns8382x_reset(struct eth_device *dev);
+static void ns8382x_init_rxfilter(struct eth_device *dev);
+static void ns8382x_init_txd(struct eth_device *dev);
+static void ns8382x_init_rxd(struct eth_device *dev);
+static void ns8382x_set_rx_mode(struct eth_device *dev);
+static void ns8382x_check_duplex(struct eth_device *dev);
+static int ns8382x_send(struct eth_device *dev, volatile void *packet,
+			int length);
+static int ns8382x_poll(struct eth_device *dev);
+static void ns8382x_disable(struct eth_device *dev);
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83820},
+	{}
+};
+
+#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+static inline int
+INW(struct eth_device *dev, u_long addr)
+{
+	return le16_to_cpu(*(vu_short *) (addr + dev->iobase));
+}
+
+static int
+INL(struct eth_device *dev, u_long addr)
+{
+	return le32_to_cpu(*(vu_long *) (addr + dev->iobase));
+}
+
+static inline void
+OUTW(struct eth_device *dev, int command, u_long addr)
+{
+	*(vu_short *) ((addr + dev->iobase)) = cpu_to_le16(command);
+}
+
+static inline void
+OUTL(struct eth_device *dev, int command, u_long addr)
+{
+	*(vu_long *) ((addr + dev->iobase)) = cpu_to_le32(command);
+}
+
+/* Function: ns8382x_initialize
+ * Description: Retrieves the MAC address of the card, and sets up some
+ *  globals required by other routines, and initializes the NIC, making it
+ *  ready to send and receive packets.
+ * Side effects: initializes ns8382xs, ready to recieve packets.
+ * Returns:   int:          number of cards found
+ */
+
+int
+ns8382x_initialize(bd_t * bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	u32 iobase, status;
+	int i, idx = 0;
+	u32 phyAddress;
+	u32 tmp;
+	u32 chip_config;
+
+	while (1) {		/* Find PCI device(s) */
+		if ((devno = pci_find_devices(supported, idx++)) < 0)
+			break;
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+		iobase &= ~0x3;	/* 1: unused and 0:I/O Space Indicator */
+
+#ifdef NS8382X_DEBUG
+		printf("ns8382x: NatSemi dp8382x @ 0x%x\n", iobase);
+#endif
+
+		pci_write_config_dword(devno, PCI_COMMAND,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+		/* Check if I/O accesses and Bus Mastering are enabled. */
+		pci_read_config_dword(devno, PCI_COMMAND, &status);
+		if (!(status & PCI_COMMAND_MEMORY)) {
+			printf("Error: Can not enable MEM access.\n");
+			continue;
+		} else if (!(status & PCI_COMMAND_MASTER)) {
+			printf("Error: Can not enable Bus Mastering.\n");
+			continue;
+		}
+
+		dev = (struct eth_device *) malloc(sizeof *dev);
+
+		sprintf(dev->name, "dp8382x#%d", card_number);
+		dev->iobase = bus_to_phys(iobase);
+		dev->priv = (void *) devno;
+		dev->init = ns8382x_init;
+		dev->halt = ns8382x_disable;
+		dev->send = ns8382x_send;
+		dev->recv = ns8382x_poll;
+
+		/* ns8382x has a non-standard PM control register
+		 * in PCI config space.  Some boards apparently need
+		 * to be brought to D0 in this manner.  */
+		pci_read_config_dword(devno, PCIPM, &tmp);
+		if (tmp & (0x03 | 0x100)) {	/* D0 state, disable PME assertion */
+			u32 newtmp = tmp & ~(0x03 | 0x100);
+			pci_write_config_dword(devno, PCIPM, newtmp);
+		}
+
+		/* get MAC address */
+		for (i = 0; i < 3; i++) {
+			u32 data;
+			char *mac = (char *)&dev->enetaddr[i * 2];
+
+			OUTL(dev, i * 2, RxFilterAddr);
+			data = INL(dev, RxFilterData);
+			*mac++ = data;
+			*mac++ = data >> 8;
+		}
+		/* get PHY address, can't be zero */
+		for (phyAddress = 1; phyAddress < 32; phyAddress++) {
+			u32 rev, phy1;
+
+			phy1 = mdio_read(dev, phyAddress, PHYIDR1);
+			if (phy1 == 0x2000) {	/*check for 83861/91 */
+				rev = mdio_read(dev, phyAddress, PHYIDR2);
+				if ((rev & ~(0x000f)) == 0x00005c50 ||
+				    (rev & ~(0x000f)) == 0x00005c60) {
+#ifdef NS8382X_DEBUG
+					printf("phy rev is %x\n", rev);
+					printf("phy address is %x\n",
+					       phyAddress);
+#endif
+					break;
+				}
+			}
+		}
+
+		/* set phy to autonegotiate && advertise everything */
+		mdio_write(dev, phyAddress, KTCR,
+			   (ktcr_adv_1000H | ktcr_adv_1000F));
+		mdio_write(dev, phyAddress, ANAR,
+			   (anar_adv_100F | anar_adv_100H | anar_adv_10H |
+			    anar_adv_10F | anar_ieee_8023));
+		mdio_write(dev, phyAddress, BMCR, 0x0);	/*restore */
+		mdio_write(dev, phyAddress, BMCR,
+			   (Bmcr_AutoNegEn | Bmcr_RstAutoNeg));
+		/* Reset the chip to erase any previous misconfiguration. */
+		OUTL(dev, (ChipReset), ChipCmd);
+
+		chip_config = INL(dev, ChipConfig);
+		/* reset the phy */
+		OUTL(dev, (chip_config | PhyRst), ChipConfig);
+		/* power up and initialize transceiver */
+		OUTL(dev, (chip_config & ~(PhyDis)), ChipConfig);
+
+		mdio_sync(dev, EECtrl);
+#ifdef NS8382X_DEBUG
+		{
+			u32 chpcfg =
+			    INL(dev, ChipConfig) ^ SpeedStatus_Polarity;
+
+			printf("%s: Transceiver 10%s %s duplex.\n", dev->name,
+			       (chpcfg & GigSpeed) ? "00" : (chpcfg & HundSpeed)
+			       ? "0" : "",
+			       chpcfg & FullDuplex ? "full" : "half");
+			printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+			       dev->enetaddr[0], dev->enetaddr[1],
+			       dev->enetaddr[2], dev->enetaddr[3],
+			       dev->enetaddr[4], dev->enetaddr[5]);
+		}
+#endif
+		/* Disable PME:
+		 * The PME bit is initialized from the EEPROM contents.
+		 * PCI cards probably have PME disabled, but motherboard
+		 * implementations may have PME set to enable WakeOnLan.
+		 * With PME set the chip will scan incoming packets but
+		 * nothing will be written to memory. */
+		SavedClkRun = INL(dev, ClkRun);
+		OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+		eth_register(dev);
+
+		card_number++;
+
+		pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x60);
+
+		udelay(10 * 1000);
+	}
+	return card_number;
+}
+
+/*  MII transceiver control section.
+	Read and write MII registers using software-generated serial MDIO
+	protocol.  See the MII specifications or DP83840A data sheet for details.
+
+	The maximum data clock rate is 2.5 Mhz.  To meet minimum timing we
+	must flush writes to the PCI bus with a PCI read. */
+#define mdio_delay(mdio_addr) INL(dev, mdio_addr)
+
+#define MDIO_EnbIn  (0)
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void
+mdio_sync(struct eth_device *dev, u32 offset)
+{
+	int bits = 32;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (--bits >= 0) {
+		OUTL(dev, MDIO_WRITE1, offset);
+		mdio_delay(offset);
+		OUTL(dev, MDIO_WRITE1 | MDIO_ShiftClk, offset);
+		mdio_delay(offset);
+	}
+}
+
+static int
+mdio_read(struct eth_device *dev, int phy_id, int addr)
+{
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | addr;
+	int i, retval = 0;
+
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		OUTL(dev, dataval, EECtrl);
+		mdio_delay(EECtrl);
+		OUTL(dev, dataval | MDIO_ShiftClk, EECtrl);
+		mdio_delay(EECtrl);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		OUTL(dev, MDIO_EnbIn, EECtrl);
+		mdio_delay(EECtrl);
+		retval =
+		    (retval << 1) | ((INL(dev, EECtrl) & MDIO_Data) ? 1 : 0);
+		OUTL(dev, MDIO_EnbIn | MDIO_ShiftClk, EECtrl);
+		mdio_delay(EECtrl);
+	}
+	return (retval >> 1) & 0xffff;
+}
+
+static void
+mdio_write(struct eth_device *dev, int phy_id, int addr, int value)
+{
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (addr << 18) | value;
+	int i;
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		OUTL(dev, dataval, EECtrl);
+		mdio_delay(EECtrl);
+		OUTL(dev, dataval | MDIO_ShiftClk, EECtrl);
+		mdio_delay(EECtrl);
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		OUTL(dev, MDIO_EnbIn, EECtrl);
+		mdio_delay(EECtrl);
+		OUTL(dev, MDIO_EnbIn | MDIO_ShiftClk, EECtrl);
+		mdio_delay(EECtrl);
+	}
+	return;
+}
+
+/* Function: ns8382x_init
+ * Description: resets the ethernet controller chip and configures
+ *    registers and data structures required for sending and receiving packets.
+ * Arguments: struct eth_device *dev:       NIC data structure
+ * returns:  	int.
+ */
+
+static int
+ns8382x_init(struct eth_device *dev, bd_t * bis)
+{
+	u32 config;
+
+	ns8382x_reset(dev);
+
+	/* Disable PME:
+	 * The PME bit is initialized from the EEPROM contents.
+	 * PCI cards probably have PME disabled, but motherboard
+	 * implementations may have PME set to enable WakeOnLan.
+	 * With PME set the chip will scan incoming packets but
+	 * nothing will be written to memory. */
+	OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+	ns8382x_init_rxfilter(dev);
+	ns8382x_init_txd(dev);
+	ns8382x_init_rxd(dev);
+
+	/*set up ChipConfig */
+	config = INL(dev, ChipConfig);
+	/*turn off 64 bit ops && Ten-bit interface
+	 * && big-endian mode && extended status */
+	config &= ~(TBIEn | Mode1000 | T64En | D64En | M64En | BEMode | PhyDis | ExtStEn);
+	OUTL(dev, config, ChipConfig);
+
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+	tx_config = TxCarrierIgn | TxHeartIgn | TxAutoPad
+	    | TxCollRetry | TxMxdma_1024 | (0x1002);
+	rx_config = RxMxdma_1024 | 0x20;
+#ifdef NS8382X_DEBUG
+	printf("%s: Setting TxConfig Register %#08X\n", dev->name, tx_config);
+	printf("%s: Setting RxConfig Register %#08X\n", dev->name, rx_config);
+#endif
+	OUTL(dev, tx_config, TxConfig);
+	OUTL(dev, rx_config, RxConfig);
+
+	/*turn off priority queueing */
+	OUTL(dev, 0x0, PriQueue);
+
+	ns8382x_check_duplex(dev);
+	ns8382x_set_rx_mode(dev);
+
+	OUTL(dev, (RxOn | TxOn), ChipCmd);
+	return 1;
+}
+
+/* Function: ns8382x_reset
+ * Description: soft resets the controller chip
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * Returns:   void.
+ */
+static void
+ns8382x_reset(struct eth_device *dev)
+{
+	OUTL(dev, ChipReset, ChipCmd);
+	while (INL(dev, ChipCmd))
+		/*wait until done */ ;
+	OUTL(dev, 0, IntrMask);
+	OUTL(dev, 0, IntrEnable);
+}
+
+/* Function: ns8382x_init_rxfilter
+ * Description: sets receive filter address to our MAC address
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * returns:   void.
+ */
+
+static void
+ns8382x_init_rxfilter(struct eth_device *dev)
+{
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		OUTL(dev, i, RxFilterAddr);
+		OUTW(dev, dev->enetaddr[i] + (dev->enetaddr[i + 1] << 8),
+		     RxFilterData);
+	}
+}
+
+/* Function: ns8382x_init_txd
+ * Description: initializes the Tx descriptor
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * returns:   void.
+ */
+
+static void
+ns8382x_init_txd(struct eth_device *dev)
+{
+	txd.link = (u32) 0;
+	txd.bufptr = cpu_to_le32((u32) & txb[0]);
+	txd.cmdsts = (u32) 0;
+	txd.extsts = (u32) 0;
+
+	OUTL(dev, 0x0, TxRingPtrHi);
+	OUTL(dev, phys_to_bus((u32)&txd), TxRingPtr);
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_init_txd: TX descriptor register loaded with: %#08X (&txd: %p)\n",
+	       INL(dev, TxRingPtr), &txd);
+#endif
+}
+
+/* Function: ns8382x_init_rxd
+ * Description: initializes the Rx descriptor ring
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * Returns:   void.
+ */
+
+static void
+ns8382x_init_rxd(struct eth_device *dev)
+{
+	int i;
+
+	OUTL(dev, 0x0, RxRingPtrHi);
+
+	cur_rx = 0;
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		rxd[i].link =
+		    cpu_to_le32((i + 1 <
+				 NUM_RX_DESC) ? (u32) & rxd[i +
+							    1] : (u32) &
+				rxd[0]);
+		rxd[i].extsts = cpu_to_le32((u32) 0x0);
+		rxd[i].cmdsts = cpu_to_le32((u32) RX_BUF_SIZE);
+		rxd[i].bufptr = cpu_to_le32((u32) & rxb[i * RX_BUF_SIZE]);
+#ifdef NS8382X_DEBUG
+		printf
+		    ("ns8382x_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n",
+		     i, &rxd[i], le32_to_cpu(rxd[i].link),
+		     le32_to_cpu(rxd[i].cmdsts), le32_to_cpu(rxd[i].bufptr));
+#endif
+	}
+	OUTL(dev, phys_to_bus((u32) & rxd), RxRingPtr);
+
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_init_rxd: RX descriptor register loaded with: %X\n",
+	       INL(dev, RxRingPtr));
+#endif
+}
+
+/* Function: ns8382x_set_rx_mode
+ * Description:
+ *    sets the receive mode to accept all broadcast packets and packets
+ *    with our MAC address, and reject all multicast packets.
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * Returns:   void.
+ */
+
+static void
+ns8382x_set_rx_mode(struct eth_device *dev)
+{
+	u32 rx_mode = 0x0;
+	/*spec says RxFilterEnable has to be 0 for rest of
+	 * this stuff to be properly configured. Linux driver
+	 * seems to support this*/
+/*	OUTL(dev, rx_mode, RxFilterAddr);*/
+	rx_mode = (RxFilterEnable | AcceptAllBroadcast | AcceptPerfectMatch);
+	OUTL(dev, rx_mode, RxFilterAddr);
+	printf("ns8382x_set_rx_mode: set to %X\n", rx_mode);
+	/*now we turn RxFilterEnable back on */
+	/*rx_mode |= RxFilterEnable;
+	OUTL(dev, rx_mode, RxFilterAddr);*/
+}
+
+static void
+ns8382x_check_duplex(struct eth_device *dev)
+{
+	int gig = 0;
+	int hun = 0;
+	int duplex = 0;
+	int config = (INL(dev, ChipConfig) ^ SpeedStatus_Polarity);
+
+	duplex = (config & FullDuplex) ? 1 : 0;
+	gig = (config & GigSpeed) ? 1 : 0;
+	hun = (config & HundSpeed) ? 1 : 0;
+#ifdef NS8382X_DEBUG
+	printf("%s: Setting 10%s %s-duplex based on negotiated link"
+	       " capability.\n", dev->name, (gig) ? "00" : (hun) ? "0" : "",
+	       duplex ? "full" : "half");
+#endif
+	if (duplex) {
+		rx_config |= RxAcceptTx;
+		tx_config |= (TxCarrierIgn | TxHeartIgn);
+	} else {
+		rx_config &= ~RxAcceptTx;
+		tx_config &= ~(TxCarrierIgn | TxHeartIgn);
+	}
+#ifdef NS8382X_DEBUG
+	printf("%s: Resetting TxConfig Register %#08X\n", dev->name, tx_config);
+	printf("%s: Resetting RxConfig Register %#08X\n", dev->name, rx_config);
+#endif
+	OUTL(dev, tx_config, TxConfig);
+	OUTL(dev, rx_config, RxConfig);
+
+	/*if speed is 10 or 100, remove MODE1000,
+	 * if it's 1000, then set it */
+	config = INL(dev, ChipConfig);
+	if (gig)
+		config |= Mode1000;
+	else
+		config &= ~Mode1000;
+
+#ifdef NS8382X_DEBUG
+	printf("%s: %setting Mode1000\n", dev->name, (gig) ? "S" : "Uns");
+#endif
+	OUTL(dev, config, ChipConfig);
+}
+
+/* Function: ns8382x_send
+ * Description: transmits a packet and waits for completion or timeout.
+ * Returns:   void.  */
+static int
+ns8382x_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	u32 i, status = 0;
+	vu_long tx_stat = 0;
+
+	/* Stop the transmitter */
+	OUTL(dev, TxOff, ChipCmd);
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_send: sending %d bytes\n", (int)length);
+#endif
+
+	/* set the transmit buffer descriptor and enable Transmit State Machine */
+	txd.link = cpu_to_le32(0x0);
+	txd.bufptr = cpu_to_le32(phys_to_bus((u32)packet));
+	txd.extsts = cpu_to_le32(0x0);
+	txd.cmdsts = cpu_to_le32(DescOwn | length);
+
+	/* load Transmit Descriptor Register */
+	OUTL(dev, phys_to_bus((u32) & txd), TxRingPtr);
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_send: TX descriptor register loaded with: %#08X\n",
+	       INL(dev, TxRingPtr));
+	printf("\ttxd.link:%X\tbufp:%X\texsts:%X\tcmdsts:%X\n",
+	       le32_to_cpu(txd.link), le32_to_cpu(txd.bufptr),
+	       le32_to_cpu(txd.extsts), le32_to_cpu(txd.cmdsts));
+#endif
+	/* restart the transmitter */
+	OUTL(dev, TxOn, ChipCmd);
+
+	for (i = 0; (tx_stat = le32_to_cpu(txd.cmdsts)) & DescOwn; i++) {
+		if (i >= TOUT_LOOP) {
+			printf ("%s: tx error buffer not ready: txd.cmdsts %#X\n",
+			     dev->name, tx_stat);
+			goto Done;
+		}
+	}
+
+	if (!(tx_stat & DescPktOK)) {
+		printf("ns8382x_send: Transmit error, Tx status %X.\n", tx_stat);
+		goto Done;
+	}
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_send: tx_stat: %#08X\n", tx_stat);
+#endif
+
+	status = 1;
+      Done:
+	return status;
+}
+
+/* Function: ns8382x_poll
+ * Description: checks for a received packet and returns it if found.
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * Returns:   1 if    packet was received.
+ *            0 if no packet was received.
+ * Side effects:
+ *            Returns (copies) the packet to the array dev->packet.
+ *            Returns the length of the packet.
+ */
+
+static int
+ns8382x_poll(struct eth_device *dev)
+{
+	int retstat = 0;
+	int length = 0;
+	vu_long rx_status = le32_to_cpu(rxd[cur_rx].cmdsts);
+
+	if (!(rx_status & (u32) DescOwn))
+		return retstat;
+#ifdef NS8382X_DEBUG
+	printf("ns8382x_poll: got a packet: cur_rx:%u, status:%lx\n",
+	       cur_rx, rx_status);
+#endif
+	length = (rx_status & DSIZE) - CRC_SIZE;
+
+	if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
+		/* corrupted packet received */
+		printf("ns8382x_poll: Corrupted packet, status:%lx\n", rx_status);
+		retstat = 0;
+	} else {
+		/* give packet to higher level routine */
+		NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+		retstat = 1;
+	}
+
+	/* return the descriptor and buffer to receive ring */
+	rxd[cur_rx].cmdsts = cpu_to_le32(RX_BUF_SIZE);
+	rxd[cur_rx].bufptr = cpu_to_le32((u32) & rxb[cur_rx * RX_BUF_SIZE]);
+
+	if (++cur_rx == NUM_RX_DESC)
+		cur_rx = 0;
+
+	/* re-enable the potentially idle receive state machine */
+	OUTL(dev, RxOn, ChipCmd);
+
+	return retstat;
+}
+
+/* Function: ns8382x_disable
+ * Description: Turns off interrupts and stops Tx and Rx engines
+ * Arguments: struct eth_device *dev:          NIC data structure
+ * Returns:   void.
+ */
+
+static void
+ns8382x_disable(struct eth_device *dev)
+{
+	/* Disable interrupts using the mask. */
+	OUTL(dev, 0, IntrMask);
+	OUTL(dev, 0, IntrEnable);
+
+	/* Stop the chip's Tx and Rx processes. */
+	OUTL(dev, (RxOff | TxOff), ChipCmd);
+
+	/* Restore PME enable bit */
+	OUTL(dev, SavedClkRun, ClkRun);
+}
+
+#endif
diff --git a/drivers/net/ns9750_eth.c b/drivers/net/ns9750_eth.c
new file mode 100644
index 0000000..067ff8e
--- /dev/null
+++ b/drivers/net/ns9750_eth.c
@@ -0,0 +1,797 @@
+/***********************************************************************
+ *
+ * Copyright (C) 2004 by FS Forth-Systeme GmbH.
+ * All rights reserved.
+ *
+ * $Id: ns9750_eth.c,v 1.2 2004/02/24 14:09:39 mpietrek Exp $
+ * @Author: Markus Pietrek
+ * @Descr: Ethernet driver for the NS9750. Uses DMA Engine with polling
+ *	   interrupt status. But interrupts are not enabled.
+ *	   Only one tx buffer descriptor and the RXA buffer descriptor are used
+ *	   Currently no transmit lockup handling is included. eth_send has a 5s
+ *	   timeout for sending frames. No retransmits are performed when an
+ *	   error occurs.
+ * @References: [1] NS9750 Hardware Reference, December 2003
+ *		[2] Intel LXT971 Datasheet #249414 Rev. 02
+ *		[3] NS7520 Linux Ethernet Driver
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ***********************************************************************/
+
+#include <common.h>
+#include <net.h>		/* NetSendPacket */
+
+#include "ns9750_eth.h"		/* for Ethernet and PHY */
+
+#ifdef CONFIG_DRIVER_NS9750_ETHERNET
+
+/* some definition to make transistion to linux easier */
+
+#define NS9750_DRIVER_NAME	"eth"
+#define KERN_WARNING		"Warning:"
+#define KERN_ERR		"Error:"
+#define KERN_INFO		"Info:"
+
+#if 0
+# define DEBUG
+#endif
+
+#ifdef	DEBUG
+# define printk			printf
+
+# define DEBUG_INIT		0x0001
+# define DEBUG_MINOR		0x0002
+# define DEBUG_RX		0x0004
+# define DEBUG_TX		0x0008
+# define DEBUG_INT		0x0010
+# define DEBUG_POLL		0x0020
+# define DEBUG_LINK		0x0040
+# define DEBUG_MII		0x0100
+# define DEBUG_MII_LOW		0x0200
+# define DEBUG_MEM		0x0400
+# define DEBUG_ERROR		0x4000
+# define DEBUG_ERROR_CRIT	0x8000
+
+static int nDebugLvl = DEBUG_ERROR_CRIT;
+
+# define DEBUG_ARGS0( FLG, a0 ) if( ( nDebugLvl & (FLG) ) == (FLG) ) \
+		printf("%s: " a0, __FUNCTION__, 0, 0, 0, 0, 0, 0 )
+# define DEBUG_ARGS1( FLG, a0, a1 ) if( ( nDebugLvl & (FLG) ) == (FLG)) \
+		printf("%s: " a0, __FUNCTION__, (int)(a1), 0, 0, 0, 0, 0 )
+# define DEBUG_ARGS2( FLG, a0, a1, a2 ) if( (nDebugLvl & (FLG)) ==(FLG))\
+		printf("%s: " a0, __FUNCTION__, (int)(a1), (int)(a2), 0, 0,0,0 )
+# define DEBUG_ARGS3( FLG, a0, a1, a2, a3 ) if((nDebugLvl &(FLG))==(FLG))\
+		printf("%s: "a0,__FUNCTION__,(int)(a1),(int)(a2),(int)(a3),0,0,0)
+# define DEBUG_FN( FLG ) if( (nDebugLvl & (FLG)) == (FLG) ) \
+		printf("\r%s:line %d\n", (int)__FUNCTION__, __LINE__, 0,0,0,0);
+# define ASSERT( expr, func ) if( !( expr ) ) { \
+		printf( "Assertion failed! %s:line %d %s\n", \
+		(int)__FUNCTION__,__LINE__,(int)(#expr),0,0,0); \
+		func }
+#else /* DEBUG */
+# define printk(...)
+# define DEBUG_ARGS0( FLG, a0 )
+# define DEBUG_ARGS1( FLG, a0, a1 )
+# define DEBUG_ARGS2( FLG, a0, a1, a2 )
+# define DEBUG_ARGS3( FLG, a0, a1, a2, a3 )
+# define DEBUG_FN( n )
+# define ASSERT(expr, func)
+#endif /* DEBUG */
+
+#define NS9750_MII_NEG_DELAY		(5*CFG_HZ) /* in s */
+#define TX_TIMEOUT			(5*CFG_HZ) /* in s */
+
+/* @TODO move it to eeprom.h */
+#define FS_EEPROM_AUTONEG_MASK		0x7
+#define FS_EEPROM_AUTONEG_SPEED_MASK	0x1
+#define FS_EEPROM_AUTONEG_SPEED_10	0x0
+#define FS_EEPROM_AUTONEG_SPEED_100	0x1
+#define FS_EEPROM_AUTONEG_DUPLEX_MASK	0x2
+#define FS_EEPROM_AUTONEG_DUPLEX_HALF	0x0
+#define FS_EEPROM_AUTONEG_DUPLEX_FULL	0x2
+#define FS_EEPROM_AUTONEG_ENABLE_MASK	0x4
+#define FS_EEPROM_AUTONEG_DISABLE	0x0
+#define FS_EEPROM_AUTONEG_ENABLE	0x4
+
+/* buffer descriptors taken from [1] p.306 */
+typedef struct
+{
+	unsigned int* punSrc;
+	unsigned int unLen;	/* 11 bits */
+	unsigned int* punDest;	/* unused */
+	union {
+		unsigned int unReg;
+		struct {
+			unsigned uStatus : 16;
+			unsigned uRes : 12;
+			unsigned uFull : 1;
+			unsigned uEnable : 1;
+			unsigned uInt : 1;
+			unsigned uWrap : 1;
+		} bits;
+	} s;
+} rx_buffer_desc_t;
+
+typedef struct
+{
+	unsigned int* punSrc;
+	unsigned int unLen;	/* 10 bits */
+	unsigned int* punDest;	/* unused */
+	union {
+		unsigned int unReg; /* only 32bit accesses may done to NS9750
+				     * eth engine */
+		struct {
+			unsigned uStatus : 16;
+			unsigned uRes : 12;
+			unsigned uFull : 1;
+			unsigned uLast : 1;
+			unsigned uInt : 1;
+			unsigned uWrap : 1;
+		} bits;
+	} s;
+} tx_buffer_desc_t;
+
+static int ns9750_eth_reset( void );
+
+static void ns9750_link_force( void );
+static void ns9750_link_auto_negotiate( void );
+static void ns9750_link_update_egcr( void );
+static void ns9750_link_print_changed( void );
+
+/* the PHY stuff */
+
+static char ns9750_mii_identify_phy( void );
+static unsigned short ns9750_mii_read( unsigned short uiRegister );
+static void ns9750_mii_write( unsigned short uiRegister, unsigned short uiData );
+static unsigned int ns9750_mii_get_clock_divisor( unsigned int unMaxMDIOClk );
+static unsigned int ns9750_mii_poll_busy( void );
+
+static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
+static unsigned char ucLinkMode =      FS_EEPROM_AUTONEG_ENABLE;
+static unsigned int uiLastLinkStatus;
+static PhyType phyDetected = PHY_NONE;
+
+/* we use only one tx buffer descriptor */
+static tx_buffer_desc_t* pTxBufferDesc =
+	(tx_buffer_desc_t*) get_eth_reg_addr( NS9750_ETH_TXBD );
+
+/* we use only one rx buffer descriptor of the 4 */
+static rx_buffer_desc_t aRxBufferDesc[ 4 ];
+
+/***********************************************************************
+ * @Function: eth_init
+ * @Return: -1 on failure otherwise 0
+ * @Descr: Initializes the ethernet engine and uses either FS Forth's default
+ *	   MAC addr or the one in environment
+ ***********************************************************************/
+
+int eth_init (bd_t * pbis)
+{
+	/* This default MAC Addr is reserved by FS Forth-Systeme for the case of
+	   EEPROM failures */
+	unsigned char aucMACAddr[6] = { 0x00, 0x04, 0xf3, 0x00, 0x06, 0x35 };
+	char *pcTmp = getenv ("ethaddr");
+	char *pcEnd;
+	int i;
+
+	DEBUG_FN (DEBUG_INIT);
+
+	/* no need to check for hardware */
+
+	if (!ns9750_eth_reset ())
+		return -1;
+
+	if (pcTmp != NULL)
+		for (i = 0; i < 6; i++) {
+			aucMACAddr[i] =
+				pcTmp ? simple_strtoul (pcTmp, &pcEnd,
+							16) : 0;
+			pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
+		}
+
+	/* configure ethernet address */
+
+	*get_eth_reg_addr (NS9750_ETH_SA1) =
+		aucMACAddr[5] << 8 | aucMACAddr[4];
+	*get_eth_reg_addr (NS9750_ETH_SA2) =
+		aucMACAddr[3] << 8 | aucMACAddr[2];
+	*get_eth_reg_addr (NS9750_ETH_SA3) =
+		aucMACAddr[1] << 8 | aucMACAddr[0];
+
+	/* enable hardware */
+
+	*get_eth_reg_addr (NS9750_ETH_MAC1) = NS9750_ETH_MAC1_RXEN;
+
+	/* the linux kernel may give packets < 60 bytes, for example arp */
+	*get_eth_reg_addr (NS9750_ETH_MAC2) = NS9750_ETH_MAC2_CRCEN |
+		NS9750_ETH_MAC2_PADEN | NS9750_ETH_MAC2_HUGE;
+
+	/* enable receive and transmit FIFO, use 10/100 Mbps MII */
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) =
+		NS9750_ETH_EGCR1_ETXWM |
+		NS9750_ETH_EGCR1_ERX |
+		NS9750_ETH_EGCR1_ERXDMA |
+		NS9750_ETH_EGCR1_ETX |
+		NS9750_ETH_EGCR1_ETXDMA | NS9750_ETH_EGCR1_ITXA;
+
+	/* prepare DMA descriptors */
+	for (i = 0; i < 4; i++) {
+		aRxBufferDesc[i].punSrc = 0;
+		aRxBufferDesc[i].unLen = 0;
+		aRxBufferDesc[i].s.bits.uWrap = 1;
+		aRxBufferDesc[i].s.bits.uInt = 1;
+		aRxBufferDesc[i].s.bits.uEnable = 0;
+		aRxBufferDesc[i].s.bits.uFull = 0;
+	}
+
+	/* NetRxPackets[ 0 ] is initialized before eth_init is called and never
+	   changes. NetRxPackets is 32bit aligned */
+	aRxBufferDesc[0].punSrc = (unsigned int *) NetRxPackets[0];
+	aRxBufferDesc[0].s.bits.uEnable = 1;
+	aRxBufferDesc[0].unLen = 1522;	/* as stated in [1] p.307 */
+
+	*get_eth_reg_addr (NS9750_ETH_RXAPTR) =
+		(unsigned int) &aRxBufferDesc[0];
+
+	/* [1] Tab. 221 states less than 5us */
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_ERXINIT;
+	while (!
+	       (*get_eth_reg_addr (NS9750_ETH_EGSR) & NS9750_ETH_EGSR_RXINIT))
+		/* wait for finish */
+		udelay (1);
+
+	/* @TODO do we need to clear RXINIT? */
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_ERXINIT;
+
+	*get_eth_reg_addr (NS9750_ETH_RXFREE) = 0x1;
+
+	return 0;
+}
+
+/***********************************************************************
+ * @Function: eth_send
+ * @Return: -1 on timeout otherwise 1
+ * @Descr: sends one frame by DMA
+ ***********************************************************************/
+
+int eth_send (volatile void *pPacket, int nLen)
+{
+	ulong ulTimeout;
+
+	DEBUG_FN (DEBUG_TX);
+
+	/* clear old status values */
+	*get_eth_reg_addr (NS9750_ETH_EINTR) &=
+		*get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_TX_MA;
+
+	/* prepare Tx Descriptors */
+
+	pTxBufferDesc->punSrc = (unsigned int *) pPacket;	/* pPacket is 32bit
+								 * aligned */
+	pTxBufferDesc->unLen = nLen;
+	/* only 32bit accesses allowed. wrap, full, interrupt and enabled to 1 */
+	pTxBufferDesc->s.unReg = 0xf0000000;
+	/* pTxBufferDesc is the first possible buffer descriptor */
+	*get_eth_reg_addr (NS9750_ETH_TXPTR) = 0x0;
+
+	/* enable processor for next frame */
+
+	*get_eth_reg_addr (NS9750_ETH_EGCR2) &= ~NS9750_ETH_EGCR2_TCLER;
+	*get_eth_reg_addr (NS9750_ETH_EGCR2) |= NS9750_ETH_EGCR2_TCLER;
+
+	ulTimeout = get_timer (0);
+
+	DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR,
+		     "Waiting for transmission to finish\n");
+	while (!
+	       (*get_eth_reg_addr (NS9750_ETH_EINTR) &
+		(NS9750_ETH_EINTR_TXDONE | NS9750_ETH_EINTR_TXERR))) {
+		/* do nothing, wait for completion */
+		if (get_timer (0) - ulTimeout > TX_TIMEOUT) {
+			DEBUG_ARGS0 (DEBUG_TX, "Transmit Timed out\n");
+			return -1;
+		}
+	}
+	DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR, "transmitted...\n");
+
+	return 0;
+}
+
+/***********************************************************************
+ * @Function: eth_rx
+ * @Return: size of last frame in bytes or 0 if no frame available
+ * @Descr: gives one frame to U-Boot which has been copied by DMA engine already
+ *	   to NetRxPackets[ 0 ].
+ ***********************************************************************/
+
+int eth_rx (void)
+{
+	int nLen = 0;
+	unsigned int unStatus;
+
+	unStatus =
+		*get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_RX_MA;
+
+	if (!unStatus)
+		/* no packet available, return immediately */
+		return 0;
+
+	DEBUG_FN (DEBUG_RX);
+
+	/* unLen always < max(nLen) and discard checksum */
+	nLen = (int) aRxBufferDesc[0].unLen - 4;
+
+	/* acknowledge status register */
+	*get_eth_reg_addr (NS9750_ETH_EINTR) = unStatus;
+
+	aRxBufferDesc[0].unLen = 1522;
+	aRxBufferDesc[0].s.bits.uFull = 0;
+
+	/* Buffer A descriptor available again */
+	*get_eth_reg_addr (NS9750_ETH_RXFREE) |= 0x1;
+
+	/* NetReceive may call eth_send. Due to a possible bug of the NS9750 we
+	 * have to acknowledge the received frame before sending a new one */
+	if (unStatus & NS9750_ETH_EINTR_RXDONEA)
+		NetReceive (NetRxPackets[0], nLen);
+
+	return nLen;
+}
+
+/***********************************************************************
+ * @Function: eth_halt
+ * @Return: n/a
+ * @Descr: stops the ethernet engine
+ ***********************************************************************/
+
+void eth_halt (void)
+{
+	DEBUG_FN (DEBUG_INIT);
+
+	*get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_RXEN;
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~(NS9750_ETH_EGCR1_ERX |
+						  NS9750_ETH_EGCR1_ERXDMA |
+						  NS9750_ETH_EGCR1_ETX |
+						  NS9750_ETH_EGCR1_ETXDMA);
+}
+
+/***********************************************************************
+ * @Function: ns9750_eth_reset
+ * @Return: 0 on failure otherwise 1
+ * @Descr: resets the ethernet interface and the PHY,
+ *	   performs auto negotiation or fixed modes
+ ***********************************************************************/
+
+static int ns9750_eth_reset (void)
+{
+	DEBUG_FN (DEBUG_MINOR);
+
+	/* Reset MAC */
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_MAC_HRST;
+	udelay (5);		/* according to [1], p.322 */
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_MAC_HRST;
+
+	/* reset and initialize PHY */
+
+	*get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_SRST;
+
+	/* we don't support hot plugging of PHY, therefore we don't reset
+	   phyDetected and nPhyMaxMdioClock here. The risk is if the setting is
+	   incorrect the first open
+	   may detect the PHY correctly but succeding will fail
+	   For reseting the PHY and identifying we have to use the standard
+	   MDIO CLOCK value 2.5 MHz only after hardware reset
+	   After having identified the PHY we will do faster */
+
+	*get_eth_reg_addr (NS9750_ETH_MCFG) =
+		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);
+
+	/* reset PHY */
+	ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);
+	ns9750_mii_write (PHY_COMMON_CTRL, 0);
+
+	/* @TODO check time */
+	udelay (3000);		/* [2] p.70 says at least 300us reset recovery time. But
+				   go sure, it didn't worked stable at higher timer
+				   frequencies under LxNETES-2.x */
+
+	/* MII clock has been setup to default, ns9750_mii_identify_phy should
+	   work for all */
+
+	if (!ns9750_mii_identify_phy ()) {
+		printk (KERN_ERR NS9750_DRIVER_NAME
+			": Unsupported PHY, aborting\n");
+		return 0;
+	}
+
+	/* now take the highest MDIO clock possible after detection */
+	*get_eth_reg_addr (NS9750_ETH_MCFG) =
+		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);
+
+
+	/* PHY has been detected, so there can be no abort reason and we can
+	   finish initializing ethernet */
+
+	uiLastLinkStatus = 0xff;	/* undefined */
+
+	if ((ucLinkMode & FS_EEPROM_AUTONEG_ENABLE_MASK) ==
+	    FS_EEPROM_AUTONEG_DISABLE)
+		/* use parameters defined */
+		ns9750_link_force ();
+	else
+		ns9750_link_auto_negotiate ();
+
+	if (phyDetected == PHY_LXT971A)
+		/* set LED2 to link mode */
+		ns9750_mii_write (PHY_LXT971_LED_CFG,
+				  PHY_LXT971_LED_CFG_LINK_ACT <<
+				  PHY_LXT971_LED_CFG_SHIFT_LED2);
+
+	return 1;
+}
+
+/***********************************************************************
+ * @Function: ns9750_link_force
+ * @Return: void
+ * @Descr: configures eth and MII to use the link mode defined in
+ *	   ucLinkMode
+ ***********************************************************************/
+
+static void ns9750_link_force (void)
+{
+	unsigned short uiControl;
+
+	DEBUG_FN (DEBUG_LINK);
+
+	uiControl = ns9750_mii_read (PHY_COMMON_CTRL);
+	uiControl &= ~(PHY_COMMON_CTRL_SPD_MA |
+		       PHY_COMMON_CTRL_AUTO_NEG | PHY_COMMON_CTRL_DUPLEX);
+
+	uiLastLinkStatus = 0;
+
+	if ((ucLinkMode & FS_EEPROM_AUTONEG_SPEED_MASK) ==
+	    FS_EEPROM_AUTONEG_SPEED_100) {
+		uiControl |= PHY_COMMON_CTRL_SPD_100;
+		uiLastLinkStatus |= PHY_LXT971_STAT2_100BTX;
+	} else
+		uiControl |= PHY_COMMON_CTRL_SPD_10;
+
+	if ((ucLinkMode & FS_EEPROM_AUTONEG_DUPLEX_MASK) ==
+	    FS_EEPROM_AUTONEG_DUPLEX_FULL) {
+		uiControl |= PHY_COMMON_CTRL_DUPLEX;
+		uiLastLinkStatus |= PHY_LXT971_STAT2_DUPLEX_MODE;
+	}
+
+	ns9750_mii_write (PHY_COMMON_CTRL, uiControl);
+
+	ns9750_link_print_changed ();
+	ns9750_link_update_egcr ();
+}
+
+/***********************************************************************
+ * @Function: ns9750_link_auto_negotiate
+ * @Return: void
+ * @Descr: performs auto-negotation of link.
+ ***********************************************************************/
+
+static void ns9750_link_auto_negotiate (void)
+{
+	unsigned long ulStartJiffies;
+	unsigned short uiStatus;
+
+	DEBUG_FN (DEBUG_LINK);
+
+	/* run auto-negotation */
+	/* define what we are capable of */
+	ns9750_mii_write (PHY_COMMON_AUTO_ADV,
+			  PHY_COMMON_AUTO_ADV_100BTXFD |
+			  PHY_COMMON_AUTO_ADV_100BTX |
+			  PHY_COMMON_AUTO_ADV_10BTFD |
+			  PHY_COMMON_AUTO_ADV_10BT |
+			  PHY_COMMON_AUTO_ADV_802_3);
+	/* start auto-negotiation */
+	ns9750_mii_write (PHY_COMMON_CTRL,
+			  PHY_COMMON_CTRL_AUTO_NEG |
+			  PHY_COMMON_CTRL_RES_AUTO);
+
+	/* wait for completion */
+
+	ulStartJiffies = get_ticks ();
+	while (get_ticks () < ulStartJiffies + NS9750_MII_NEG_DELAY) {
+		uiStatus = ns9750_mii_read (PHY_COMMON_STAT);
+		if ((uiStatus &
+		     (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) ==
+		    (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) {
+			/* lucky we are, auto-negotiation succeeded */
+			ns9750_link_print_changed ();
+			ns9750_link_update_egcr ();
+			return;
+		}
+	}
+
+	DEBUG_ARGS0 (DEBUG_LINK, "auto-negotiation timed out\n");
+	/* ignore invalid link settings */
+}
+
+/***********************************************************************
+ * @Function: ns9750_link_update_egcr
+ * @Return: void
+ * @Descr: updates the EGCR and MAC2 link status after mode change or
+ *	   auto-negotation
+ ***********************************************************************/
+
+static void ns9750_link_update_egcr (void)
+{
+	unsigned int unEGCR;
+	unsigned int unMAC2;
+	unsigned int unIPGT;
+
+	DEBUG_FN (DEBUG_LINK);
+
+	unEGCR = *get_eth_reg_addr (NS9750_ETH_EGCR1);
+	unMAC2 = *get_eth_reg_addr (NS9750_ETH_MAC2);
+	unIPGT = *get_eth_reg_addr (NS9750_ETH_IPGT) & ~NS9750_ETH_IPGT_MA;
+
+	unMAC2 &= ~NS9750_ETH_MAC2_FULLD;
+	if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)
+	    == PHY_LXT971_STAT2_DUPLEX_MODE) {
+		unMAC2 |= NS9750_ETH_MAC2_FULLD;
+		unIPGT |= 0x15; /* see [1] p. 339 */
+	} else
+		unIPGT |= 0x12; /* see [1] p. 339 */
+
+	*get_eth_reg_addr (NS9750_ETH_MAC2) = unMAC2;
+	*get_eth_reg_addr (NS9750_ETH_EGCR1) = unEGCR;
+	*get_eth_reg_addr (NS9750_ETH_IPGT) = unIPGT;
+}
+
+/***********************************************************************
+ * @Function: ns9750_link_print_changed
+ * @Return: void
+ * @Descr: checks whether the link status has changed and if so prints
+ *	   the new mode
+ ***********************************************************************/
+
+static void ns9750_link_print_changed (void)
+{
+	unsigned short uiStatus;
+	unsigned short uiControl;
+
+	DEBUG_FN (DEBUG_LINK);
+
+	uiControl = ns9750_mii_read (PHY_COMMON_CTRL);
+
+	if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) ==
+	    PHY_COMMON_CTRL_AUTO_NEG) {
+		/* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */
+		uiStatus = ns9750_mii_read (PHY_COMMON_STAT);
+
+		if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) {
+			printk (KERN_WARNING NS9750_DRIVER_NAME
+				": link down\n");
+			/* @TODO Linux: carrier_off */
+		} else {
+			/* @TODO Linux: carrier_on */
+			if (phyDetected == PHY_LXT971A) {
+				uiStatus = ns9750_mii_read (PHY_LXT971_STAT2);
+				uiStatus &= (PHY_LXT971_STAT2_100BTX |
+					     PHY_LXT971_STAT2_DUPLEX_MODE |
+					     PHY_LXT971_STAT2_AUTO_NEG);
+
+				/* mask out all uninteresting parts */
+			}
+			/* other PHYs must store there link information in
+			   uiStatus as PHY_LXT971 */
+		}
+	} else {
+		/* mode has been forced, so uiStatus should be the same as the
+		   last link status, enforce printing */
+		uiStatus = uiLastLinkStatus;
+		uiLastLinkStatus = 0xff;
+	}
+
+	if (uiStatus != uiLastLinkStatus) {
+		/* save current link status */
+		uiLastLinkStatus = uiStatus;
+
+		/* print new link status */
+
+		printk (KERN_INFO NS9750_DRIVER_NAME
+			": link mode %i Mbps %s duplex %s\n",
+			(uiStatus & PHY_LXT971_STAT2_100BTX) ? 100 : 10,
+			(uiStatus & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" :
+			"half",
+			(uiStatus & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" :
+			"");
+	}
+}
+
+/***********************************************************************
+ * the MII low level stuff
+ ***********************************************************************/
+
+/***********************************************************************
+ * @Function: ns9750_mii_identify_phy
+ * @Return: 1 if supported PHY has been detected otherwise 0
+ * @Descr: checks for supported PHY and prints the IDs.
+ ***********************************************************************/
+
+static char ns9750_mii_identify_phy (void)
+{
+	unsigned short uiID1;
+	unsigned short uiID2;
+	unsigned char *szName;
+	char cRes = 0;
+
+	DEBUG_FN (DEBUG_MII);
+
+	phyDetected = (PhyType) uiID1 = ns9750_mii_read (PHY_COMMON_ID1);
+
+	switch (phyDetected) {
+	case PHY_LXT971A:
+		szName = "LXT971A";
+		uiID2 = ns9750_mii_read (PHY_COMMON_ID2);
+		nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK;
+		cRes = 1;
+		break;
+	case PHY_NONE:
+	default:
+		/* in case uiID1 == 0 && uiID2 == 0 we may have the wrong
+		   address or reset sets the wrong NS9750_ETH_MCFG_CLKS */
+
+		uiID2 = 0;
+		szName = "unknown";
+		nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
+		phyDetected = PHY_NONE;
+	}
+
+	printk (KERN_INFO NS9750_DRIVER_NAME
+		": PHY (0x%x, 0x%x) = %s detected\n", uiID1, uiID2, szName);
+
+	return cRes;
+}
+
+/***********************************************************************
+ * @Function: ns9750_mii_read
+ * @Return: the data read from PHY register uiRegister
+ * @Descr: the data read may be invalid if timed out. If so, a message
+ *	   is printed but the invalid data is returned.
+ *	   The fixed device address is being used.
+ ***********************************************************************/
+
+static unsigned short ns9750_mii_read (unsigned short uiRegister)
+{
+	DEBUG_FN (DEBUG_MII_LOW);
+
+	/* write MII register to be read */
+	*get_eth_reg_addr (NS9750_ETH_MADR) =
+		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;
+
+	*get_eth_reg_addr (NS9750_ETH_MCMD) = NS9750_ETH_MCMD_READ;
+
+	if (!ns9750_mii_poll_busy ())
+		printk (KERN_WARNING NS9750_DRIVER_NAME
+			": MII still busy in read\n");
+	/* continue to read */
+
+	*get_eth_reg_addr (NS9750_ETH_MCMD) = 0;
+
+	return (unsigned short) (*get_eth_reg_addr (NS9750_ETH_MRDD));
+}
+
+
+/***********************************************************************
+ * @Function: ns9750_mii_write
+ * @Return: nothing
+ * @Descr: writes the data to the PHY register. In case of a timeout,
+ *	   no special handling is performed but a message printed
+ *	   The fixed device address is being used.
+ ***********************************************************************/
+
+static void ns9750_mii_write (unsigned short uiRegister,
+			      unsigned short uiData)
+{
+	DEBUG_FN (DEBUG_MII_LOW);
+
+	/* write MII register to be written */
+	*get_eth_reg_addr (NS9750_ETH_MADR) =
+		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;
+
+	*get_eth_reg_addr (NS9750_ETH_MWTD) = uiData;
+
+	if (!ns9750_mii_poll_busy ()) {
+		printf (KERN_WARNING NS9750_DRIVER_NAME
+			": MII still busy in write\n");
+	}
+}
+
+
+/***********************************************************************
+ * @Function: ns9750_mii_get_clock_divisor
+ * @Return: the clock divisor that should be used in NS9750_ETH_MCFG_CLKS
+ * @Descr: if no clock divisor can be calculated for the
+ *	   current SYSCLK and the maximum MDIO Clock, a warning is printed
+ *	   and the greatest divisor is taken
+ ***********************************************************************/
+
+static unsigned int ns9750_mii_get_clock_divisor (unsigned int unMaxMDIOClk)
+{
+	struct {
+		unsigned int unSysClkDivisor;
+		unsigned int unClks;	/* field for NS9750_ETH_MCFG_CLKS */
+	} PHYClockDivisors[] = {
+		{
+		4, NS9750_ETH_MCFG_CLKS_4}, {
+		6, NS9750_ETH_MCFG_CLKS_6}, {
+		8, NS9750_ETH_MCFG_CLKS_8}, {
+		10, NS9750_ETH_MCFG_CLKS_10}, {
+		20, NS9750_ETH_MCFG_CLKS_20}, {
+		30, NS9750_ETH_MCFG_CLKS_30}, {
+		40, NS9750_ETH_MCFG_CLKS_40}
+	};
+
+	int nIndexSysClkDiv;
+	int nArraySize =
+		sizeof (PHYClockDivisors) / sizeof (PHYClockDivisors[0]);
+	unsigned int unClks = NS9750_ETH_MCFG_CLKS_40;	/* defaults to
+							   greatest div */
+
+	DEBUG_FN (DEBUG_INIT);
+
+	for (nIndexSysClkDiv = 0; nIndexSysClkDiv < nArraySize;
+	     nIndexSysClkDiv++) {
+		/* find first sysclock divisor that isn't higher than 2.5 MHz
+		   clock */
+		if (AHB_CLK_FREQ /
+		    PHYClockDivisors[nIndexSysClkDiv].unSysClkDivisor <=
+		    unMaxMDIOClk) {
+			unClks = PHYClockDivisors[nIndexSysClkDiv].unClks;
+			break;
+		}
+	}
+
+	DEBUG_ARGS2 (DEBUG_INIT,
+		     "Taking MDIO Clock bit mask 0x%0x for max clock %i\n",
+		     unClks, unMaxMDIOClk);
+
+	/* return greatest divisor */
+	return unClks;
+}
+
+/***********************************************************************
+ * @Function: ns9750_mii_poll_busy
+ * @Return: 0 if timed out otherwise the remaing timeout
+ * @Descr: waits until the MII has completed a command or it times out
+ *	   code may be interrupted by hard interrupts.
+ *	   It is not checked what happens on multiple actions when
+ *	   the first is still being busy and we timeout.
+ ***********************************************************************/
+
+static unsigned int ns9750_mii_poll_busy (void)
+{
+	unsigned int unTimeout = 10000;
+
+	DEBUG_FN (DEBUG_MII_LOW);
+
+	while (((*get_eth_reg_addr (NS9750_ETH_MIND) & NS9750_ETH_MIND_BUSY)
+		== NS9750_ETH_MIND_BUSY) && unTimeout)
+		unTimeout--;
+
+	return unTimeout;
+}
+
+#endif /* CONFIG_DRIVER_NS9750_ETHERNET */
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c
new file mode 100644
index 0000000..2af0e8f
--- /dev/null
+++ b/drivers/net/pcnet.c
@@ -0,0 +1,526 @@
+/*
+ * (C) Copyright 2002 Wolfgang Grandegger, wg@denx.de.
+ *
+ * This driver for AMD PCnet network controllers is derived from the
+ * Linux driver pcnet32.c written 1996-1999 by Thomas Bogendoerfer.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#if 0
+#define	PCNET_DEBUG_LEVEL	0 /* 0=off, 1=init, 2=rx/tx */
+#endif
+
+#if PCNET_DEBUG_LEVEL > 0
+#define	PCNET_DEBUG1(fmt,args...)	printf (fmt ,##args)
+#if PCNET_DEBUG_LEVEL > 1
+#define	PCNET_DEBUG2(fmt,args...)	printf (fmt ,##args)
+#else
+#define PCNET_DEBUG2(fmt,args...)
+#endif
+#else
+#define PCNET_DEBUG1(fmt,args...)
+#define PCNET_DEBUG2(fmt,args...)
+#endif
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_PCNET)
+
+#if !defined(CONF_PCNET_79C973) && defined(CONF_PCNET_79C975)
+#error "Macro for PCnet chip version is not defined!"
+#endif
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+ * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
+ */
+#define PCNET_LOG_TX_BUFFERS	0
+#define PCNET_LOG_RX_BUFFERS	2
+
+#define TX_RING_SIZE		(1 << (PCNET_LOG_TX_BUFFERS))
+#define TX_RING_LEN_BITS	((PCNET_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE		(1 << (PCNET_LOG_RX_BUFFERS))
+#define RX_RING_LEN_BITS	((PCNET_LOG_RX_BUFFERS) << 4)
+
+#define PKT_BUF_SZ		1544
+
+/* The PCNET Rx and Tx ring descriptors. */
+struct pcnet_rx_head {
+    u32 base;
+    s16 buf_length;
+    s16 status;
+    u32 msg_length;
+    u32 reserved;
+};
+
+struct pcnet_tx_head {
+    u32 base;
+    s16 length;
+    s16 status;
+    u32 misc;
+    u32 reserved;
+};
+
+/* The PCNET 32-Bit initialization block, described in databook. */
+struct pcnet_init_block {
+    u16 mode;
+    u16 tlen_rlen;
+    u8	phys_addr[6];
+    u16 reserved;
+    u32 filter[2];
+    /* Receive and transmit ring base, along with extra bits. */
+    u32 rx_ring;
+    u32 tx_ring;
+    u32 reserved2;
+};
+
+typedef struct pcnet_priv {
+    struct pcnet_rx_head    rx_ring[RX_RING_SIZE];
+    struct pcnet_tx_head    tx_ring[TX_RING_SIZE];
+    struct pcnet_init_block init_block;
+    /* Receive Buffer space */
+    unsigned char rx_buf[RX_RING_SIZE][PKT_BUF_SZ + 4];
+    int cur_rx;
+    int cur_tx;
+} pcnet_priv_t;
+
+static pcnet_priv_t *lp;
+
+/* Offsets from base I/O address for WIO mode */
+#define PCNET_RDP		0x10
+#define PCNET_RAP		0x12
+#define PCNET_RESET		0x14
+#define PCNET_BDP		0x16
+
+static u16 pcnet_read_csr (struct eth_device *dev, int index)
+{
+    outw (index, dev->iobase+PCNET_RAP);
+    return inw (dev->iobase+PCNET_RDP);
+}
+
+static void pcnet_write_csr (struct eth_device *dev, int index, u16 val)
+{
+    outw (index, dev->iobase+PCNET_RAP);
+    outw (val, dev->iobase+PCNET_RDP);
+}
+
+static u16 pcnet_read_bcr (struct eth_device *dev, int index)
+{
+    outw (index, dev->iobase+PCNET_RAP);
+    return inw (dev->iobase+PCNET_BDP);
+}
+
+static void pcnet_write_bcr (struct eth_device *dev, int index, u16 val)
+{
+    outw (index, dev->iobase+PCNET_RAP);
+    outw (val, dev->iobase+PCNET_BDP);
+}
+
+static void pcnet_reset (struct eth_device *dev)
+{
+    inw (dev->iobase+PCNET_RESET);
+}
+
+static int pcnet_check (struct eth_device *dev)
+{
+    outw (88, dev->iobase+PCNET_RAP);
+    return (inw (dev->iobase+PCNET_RAP) == 88);
+}
+
+static int  pcnet_init( struct eth_device* dev, bd_t *bis);
+static int  pcnet_send (struct eth_device* dev, volatile void *packet,
+			int length);
+static int  pcnet_recv (struct eth_device* dev);
+static void pcnet_halt (struct eth_device* dev);
+static int  pcnet_probe(struct eth_device* dev, bd_t *bis, int dev_num);
+
+#define PCI_TO_MEM(d,a) pci_phys_to_mem((pci_dev_t)d->priv, (u_long)(a))
+#define PCI_TO_MEM_LE(d,a) (u32)(cpu_to_le32(PCI_TO_MEM(d,a)))
+
+static struct pci_device_id supported[] = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE },
+	{ }
+};
+
+
+int pcnet_initialize(bd_t *bis)
+{
+    pci_dev_t devbusfn;
+    struct eth_device* dev;
+    u16 command, status;
+    int dev_nr = 0;
+
+    PCNET_DEBUG1("\npcnet_initialize...\n");
+
+    for (dev_nr = 0; ; dev_nr++) {
+
+	/*
+	 * Find the PCnet PCI device(s).
+	 */
+	if ((devbusfn = pci_find_devices(supported, dev_nr)) < 0) {
+	    break;
+	}
+
+	/*
+	 * Allocate and pre-fill the device structure.
+	 */
+	dev = (struct eth_device*) malloc(sizeof *dev);
+	dev->priv = (void *)devbusfn;
+	sprintf(dev->name, "pcnet#%d", dev_nr);
+
+	/*
+	 * Setup the PCI device.
+	 */
+	pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, (unsigned int *)&dev->iobase);
+	dev->iobase &= ~0xf;
+
+	PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%x: ",
+	       dev->name, devbusfn, dev->iobase);
+
+	command = PCI_COMMAND_IO | PCI_COMMAND_MASTER;
+	pci_write_config_word(devbusfn, PCI_COMMAND, command);
+	pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+	if ((status & command) != command) {
+	    printf("%s: Couldn't enable IO access or Bus Mastering\n",
+		   dev->name);
+	    free(dev);
+	    continue;
+	}
+
+	pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x40);
+
+	/*
+	 * Probe the PCnet chip.
+	 */
+	if (pcnet_probe(dev, bis, dev_nr) < 0) {
+	    free(dev);
+	    continue;
+	}
+
+	/*
+	 * Setup device structure and register the driver.
+	 */
+	dev->init   = pcnet_init;
+	dev->halt   = pcnet_halt;
+	dev->send   = pcnet_send;
+	dev->recv   = pcnet_recv;
+
+	eth_register(dev);
+    }
+
+    udelay(10 * 1000);
+
+    return dev_nr;
+}
+
+static int pcnet_probe(struct eth_device* dev, bd_t *bis, int dev_nr)
+{
+    int chip_version;
+    char *chipname;
+#ifdef PCNET_HAS_PROM
+    int i;
+#endif
+
+    /* Reset the PCnet controller */
+    pcnet_reset(dev);
+
+    /* Check if register access is working */
+    if (pcnet_read_csr(dev, 0) != 4 || !pcnet_check(dev)) {
+	printf("%s: CSR register access check failed\n", dev->name);
+	return -1;
+    }
+
+    /* Identify the chip */
+    chip_version = pcnet_read_csr(dev, 88) | (pcnet_read_csr(dev,89) << 16);
+    if ((chip_version & 0xfff) != 0x003)
+       return -1;
+    chip_version = (chip_version >> 12) & 0xffff;
+    switch (chip_version) {
+#ifdef CONFIG_PCNET_79C973
+    case 0x2625:
+	chipname = "PCnet/FAST III 79C973"; /* PCI */
+	break;
+#endif
+#ifdef CONFIG_PCNET_79C975
+    case 0x2627:
+	chipname = "PCnet/FAST III 79C975"; /* PCI */
+	break;
+#endif
+    default:
+	printf("%s: PCnet version %#x not supported\n",
+	       dev->name, chip_version);
+	return -1;
+    }
+
+    PCNET_DEBUG1("AMD %s\n", chipname);
+
+#ifdef PCNET_HAS_PROM
+    /*
+     * In most chips, after a chip reset, the ethernet address is read from
+     * the station address PROM at the base address and programmed into the
+     * "Physical Address Registers" CSR12-14.
+     */
+    for (i = 0; i < 3; i++) {
+	unsigned int val;
+	val = pcnet_read_csr(dev, i+12) & 0x0ffff;
+	/* There may be endianness issues here. */
+	dev->enetaddr[2*i  ] =  val       & 0x0ff;
+	dev->enetaddr[2*i+1] = (val >> 8) & 0x0ff;
+    }
+#endif /* PCNET_HAS_PROM */
+
+    return 0;
+}
+
+static int pcnet_init(struct eth_device* dev, bd_t *bis)
+{
+    int i, val;
+    u32 addr;
+
+    PCNET_DEBUG1("%s: pcnet_init...\n", dev->name);
+
+    /* Switch pcnet to 32bit mode */
+    pcnet_write_bcr (dev, 20, 2);
+
+#ifdef CONFIG_PN62
+    /* Setup LED registers */
+    val = pcnet_read_bcr (dev, 2) | 0x1000;
+    pcnet_write_bcr (dev, 2, val);    /* enable LEDPE */
+    pcnet_write_bcr (dev, 4, 0x5080); /* 100MBit */
+    pcnet_write_bcr (dev, 5, 0x40c0); /* LNKSE */
+    pcnet_write_bcr (dev, 6, 0x4090); /* TX Activity */
+    pcnet_write_bcr (dev, 7, 0x4084); /* RX Activity */
+#endif
+
+    /* Set/reset autoselect bit */
+    val = pcnet_read_bcr (dev, 2) & ~2;
+    val |= 2;
+    pcnet_write_bcr (dev, 2, val);
+
+    /* Enable auto negotiate, setup, disable fd */
+    val = pcnet_read_bcr(dev, 32) & ~0x98;
+    val |= 0x20;
+    pcnet_write_bcr(dev, 32, val);
+
+    /*
+     * We only maintain one structure because the drivers will never
+     * be used concurrently. In 32bit mode the RX and TX ring entries
+     * must be aligned on 16-byte boundaries.
+     */
+    if (lp == NULL) {
+	addr = (u32)malloc(sizeof(pcnet_priv_t) + 0x10);
+	addr = (addr + 0xf) & ~0xf;
+	lp = (pcnet_priv_t *)addr;
+    }
+
+    lp->init_block.mode = cpu_to_le16(0x0000);
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+
+    /*
+     * Initialize the Rx ring.
+     */
+    lp->cur_rx = 0;
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	lp->rx_ring[i].base = PCI_TO_MEM_LE(dev, lp->rx_buf[i]);
+	lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ);
+	lp->rx_ring[i].status = cpu_to_le16(0x8000);
+	PCNET_DEBUG1("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n",
+	       i, lp->rx_ring[i].base, lp->rx_ring[i].buf_length,
+	       lp->rx_ring[i].status);
+    }
+
+    /*
+     * Initialize the Tx ring. The Tx buffer address is filled in as
+     * needed, but we do need to clear the upper ownership bit.
+     */
+    lp->cur_tx = 0;
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	lp->tx_ring[i].base = 0;
+	lp->tx_ring[i].status = 0;
+    }
+
+    /*
+     * Setup Init Block.
+     */
+    PCNET_DEBUG1("Init block at 0x%p: MAC", &lp->init_block);
+
+    for (i = 0; i < 6; i++) {
+	lp->init_block.phys_addr[i] = dev->enetaddr[i];
+	PCNET_DEBUG1(" %02x", lp->init_block.phys_addr[i]);
+    }
+
+    lp->init_block.tlen_rlen = cpu_to_le16(TX_RING_LEN_BITS |
+					   RX_RING_LEN_BITS);
+    lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring);
+    lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring);
+
+    PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n",
+	   lp->init_block.tlen_rlen,
+	   lp->init_block.rx_ring, lp->init_block.tx_ring);
+
+    /*
+     * Tell the controller where the Init Block is located.
+     */
+    addr = PCI_TO_MEM(dev, &lp->init_block);
+    pcnet_write_csr(dev, 1, addr & 0xffff);
+    pcnet_write_csr(dev, 2, (addr >> 16) & 0xffff);
+
+    pcnet_write_csr (dev, 4, 0x0915);
+    pcnet_write_csr (dev, 0, 0x0001); /* start */
+
+    /* Wait for Init Done bit */
+    for (i = 10000; i > 0; i--) {
+	if (pcnet_read_csr (dev, 0) & 0x0100)
+	    break;
+	udelay(10);
+    }
+    if (i <= 0) {
+	printf("%s: TIMEOUT: controller init failed\n", dev->name);
+	pcnet_reset (dev);
+	return 0;
+    }
+
+    /*
+     * Finally start network controller operation.
+     */
+    pcnet_write_csr (dev, 0, 0x0002);
+
+    return 1;
+}
+
+static int pcnet_send(struct eth_device* dev, volatile void *packet, int pkt_len)
+{
+    int i, status;
+    struct pcnet_tx_head *entry = &lp->tx_ring[lp->cur_tx];
+
+    PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, packet);
+
+    /* Wait for completion by testing the OWN bit */
+    for (i = 1000; i > 0; i--) {
+	status = le16_to_cpu(entry->status);
+	if ((status & 0x8000) == 0)
+	    break;
+	udelay(100);
+	PCNET_DEBUG2(".");
+    }
+    if (i <= 0) {
+	printf("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n",
+	       dev->name, lp->cur_tx, status);
+	pkt_len = 0;
+	goto failure;
+    }
+
+    /*
+     * Setup Tx ring. Caution: the write order is important here,
+     * set the status with the "ownership" bits last.
+     */
+    status = 0x8300;
+    entry->length = le16_to_cpu(-pkt_len);
+    entry->misc   = 0x00000000;
+    entry->base   = PCI_TO_MEM_LE(dev, packet);
+    entry->status = le16_to_cpu(status);
+
+    /* Trigger an immediate send poll. */
+    pcnet_write_csr (dev, 0, 0x0008);
+
+ failure:
+    if (++lp->cur_tx >= TX_RING_SIZE)
+	lp->cur_tx = 0;
+
+    PCNET_DEBUG2("done\n");
+    return pkt_len;
+}
+
+static int pcnet_recv(struct eth_device* dev)
+{
+    struct pcnet_rx_head *entry;
+    int pkt_len = 0;
+    u16 status;
+
+    while (1) {
+	entry = &lp->rx_ring[lp->cur_rx];
+	/*
+	 * If we own the next entry, it's a new packet. Send it up.
+	 */
+	if (((status = le16_to_cpu(entry->status)) & 0x8000) != 0) {
+	    break;
+	}
+	status >>= 8;
+
+	if (status != 0x03) {	/* There was an error. */
+
+	    printf("%s: Rx%d", dev->name, lp->cur_rx);
+	    PCNET_DEBUG1(" (status=0x%x)", status);
+	    if (status & 0x20) printf(" Frame");
+	    if (status & 0x10) printf(" Overflow");
+	    if (status & 0x08) printf(" CRC");
+	    if (status & 0x04) printf(" Fifo");
+	    printf(" Error\n");
+	    entry->status &= le16_to_cpu(0x03ff);
+
+	} else {
+
+	    pkt_len = (le32_to_cpu(entry->msg_length) & 0xfff) - 4;
+	    if (pkt_len < 60) {
+		printf("%s: Rx%d: invalid packet length %d\n",
+		       dev->name, lp->cur_rx, pkt_len);
+	    } else {
+		NetReceive(lp->rx_buf[lp->cur_rx], pkt_len);
+		PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n",
+		       lp->cur_rx, pkt_len, lp->rx_buf[lp->cur_rx]);
+	    }
+	}
+	entry->status |= cpu_to_le16(0x8000);
+
+	if (++lp->cur_rx >= RX_RING_SIZE)
+	    lp->cur_rx = 0;
+    }
+    return pkt_len;
+}
+
+static void pcnet_halt(struct eth_device* dev)
+{
+    int i;
+
+    PCNET_DEBUG1("%s: pcnet_halt...\n", dev->name);
+
+    /* Reset the PCnet controller */
+    pcnet_reset (dev);
+
+    /* Wait for Stop bit */
+    for (i = 1000; i > 0; i--) {
+	if (pcnet_read_csr (dev, 0) & 0x4)
+	    break;
+	udelay(10);
+    }
+    if (i <= 0) {
+	printf("%s: TIMEOUT: controller reset failed\n", dev->name);
+    }
+}
+
+#endif
diff --git a/drivers/net/plb2800_eth.c b/drivers/net/plb2800_eth.c
new file mode 100644
index 0000000..0ae5d80
--- /dev/null
+++ b/drivers/net/plb2800_eth.c
@@ -0,0 +1,396 @@
+/*
+ * PLB2800 internal switch ethernet driver.
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_PLB2800_ETHER)
+
+#include <malloc.h>
+#include <net.h>
+#include <asm/addrspace.h>
+
+
+#define NUM_RX_DESC	PKTBUFSRX
+#define TOUT_LOOP	1000000
+
+#define LONG_REF(addr) (*((volatile unsigned long*)addr))
+
+#define CMAC_CRX_CTRL	LONG_REF(0xb800c870)
+#define CMAC_CTX_CTRL	LONG_REF(0xb800c874)
+#define SYS_MAC_ADDR_0	LONG_REF(0xb800c878)
+#define SYS_MAC_ADDR_1	LONG_REF(0xb800c87c)
+#define MIPS_H_MASK	LONG_REF(0xB800C810)
+
+#define MA_LEARN	LONG_REF(0xb8008004)
+#define DA_LOOKUP	LONG_REF(0xb8008008)
+
+#define CMAC_CRX_CTRL_PD	0x00000001
+#define CMAC_CRX_CTRL_CG	0x00000002
+#define CMAC_CRX_CTRL_PL_SHIFT	2
+#define CMAC_CRIT		0x0
+#define CMAC_NON_CRIT		0x1
+#define MBOX_STAT_ID_SHF	28
+#define MBOX_STAT_CP		0x80000000
+#define MBOX_STAT_MB		0x00000001
+#define EN_MA_LEARN		0x02000000
+#define EN_DA_LKUP		0x01000000
+#define MA_DEST_SHF		11
+#define DA_DEST_SHF		11
+#define DA_STATE_SHF		19
+#define TSTAMP_MS		0x00000000
+#define SW_H_MBOX4_MASK		0x08000000
+#define SW_H_MBOX3_MASK		0x04000000
+#define SW_H_MBOX2_MASK		0x02000000
+#define SW_H_MBOX1_MASK		0x01000000
+
+typedef volatile struct {
+  unsigned int stat;
+  unsigned int cmd;
+  unsigned int cnt;
+  unsigned int adr;
+} mailbox_t;
+
+#define MBOX_REG(mb) ((mailbox_t*)(0xb800c830+(mb<<4)))
+
+typedef volatile struct {
+  unsigned int word0;
+  unsigned int word1;
+  unsigned int word2;
+} mbhdr_t;
+
+#define MBOX_MEM(mb) ((void*)(0xb800a000+((3-mb)<<11)))
+
+
+static int plb2800_eth_init(struct eth_device *dev, bd_t * bis);
+static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
+						  int length);
+static int plb2800_eth_recv(struct eth_device *dev);
+static void plb2800_eth_halt(struct eth_device *dev);
+
+static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);
+static unsigned char * plb2800_get_mac_addr(void);
+
+static int rx_new;
+static int mac_addr_set = 0;
+
+
+int plb2800_eth_initialize(bd_t * bis)
+{
+	struct eth_device *dev;
+	ulong temp;
+
+#ifdef DEBUG
+	printf("Entered plb2800_eth_initialize()\n");
+#endif
+
+	if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
+	{
+		printf("Failed to allocate memory\n");
+		return 0;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	sprintf(dev->name, "PLB2800 Switch");
+	dev->init = plb2800_eth_init;
+	dev->halt = plb2800_eth_halt;
+	dev->send = plb2800_eth_send;
+	dev->recv = plb2800_eth_recv;
+
+	eth_register(dev);
+
+	/* bug fix */
+	*(ulong *)0xb800e800 = 0x838;
+
+	/* Set MBOX ownership */
+	temp = CMAC_CRIT << MBOX_STAT_ID_SHF;
+	MBOX_REG(0)->stat = temp;
+	MBOX_REG(1)->stat = temp;
+
+	temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;
+	MBOX_REG(2)->stat = temp;
+	MBOX_REG(3)->stat = temp;
+
+	plb2800_set_mac_addr(dev, plb2800_get_mac_addr());
+
+	/* Disable all Mbox interrupt */
+	temp = MIPS_H_MASK;
+	temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;
+	MIPS_H_MASK = temp;
+
+#ifdef DEBUG
+	printf("Leaving plb2800_eth_initialize()\n");
+#endif
+
+	return 1;
+}
+
+static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
+{
+#ifdef DEBUG
+	printf("Entering plb2800_eth_init()\n");
+#endif
+
+	plb2800_set_mac_addr(dev, dev->enetaddr);
+
+	rx_new = 0;
+
+#ifdef DEBUG
+	printf("Leaving plb2800_eth_init()\n");
+#endif
+
+	return 0;
+}
+
+
+static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
+						  int length)
+{
+	int                    i;
+	int                    res         = -1;
+	u32                    temp;
+	mailbox_t *            mb          = MBOX_REG(0);
+	char      *            mem         = MBOX_MEM(0);
+
+#ifdef DEBUG
+	printf("Entered plb2800_eth_send()\n");
+#endif
+
+	if (length <= 0)
+	{
+		printf ("%s: bad packet size: %d\n", dev->name, length);
+		goto Done;
+	}
+
+	if (length < 64)
+	{
+		length = 64;
+	}
+
+	temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);
+
+#ifdef DEBUG
+	printf("0 mb->stat = 0x%x\n",  mb->stat);
+#endif
+
+	for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)
+	{
+		if (i >= TOUT_LOOP)
+		{
+			printf("%s: tx buffer not ready\n", dev->name);
+			printf("1 mb->stat = 0x%x\n",  mb->stat);
+			goto Done;
+		}
+	}
+
+		/* For some strange reason, memcpy doesn't work, here!
+		 */
+	do
+	{
+		int words = (length >> 2) + 1;
+		unsigned int* dst = (unsigned int*)(mem);
+		unsigned int* src = (unsigned int*)(packet);
+		for (i = 0; i < words; i++)
+		{
+			*dst = *src;
+			dst++;
+			src++;
+		};
+	} while(0);
+
+	CMAC_CRX_CTRL = temp;
+	mb->cmd = MBOX_STAT_CP;
+
+#ifdef DEBUG
+	printf("2 mb->stat = 0x%x\n",  mb->stat);
+#endif
+
+	res = length;
+Done:
+
+#ifdef DEBUG
+	printf("Leaving plb2800_eth_send()\n");
+#endif
+
+	return res;
+}
+
+
+static int plb2800_eth_recv(struct eth_device *dev)
+{
+	int                    length  = 0;
+	mailbox_t            * mbox    = MBOX_REG(3);
+	unsigned char        * hdr     = MBOX_MEM(3);
+	unsigned int           stat;
+
+#ifdef DEBUG
+	printf("Entered plb2800_eth_recv()\n");
+#endif
+
+	for (;;)
+	{
+		stat = mbox->stat;
+
+		if (!(stat & MBOX_STAT_CP))
+		{
+			break;
+		}
+
+		length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);
+		memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);
+
+		stat &= ~MBOX_STAT_CP;
+		mbox->stat = stat;
+#ifdef DEBUG
+		{
+			int i;
+			for (i=0;i<length - 4;i++)
+			{
+				if (i % 16 == 0) printf("\n%04x: ", i);
+				printf("%02X ", NetRxPackets[rx_new][i]);
+			}
+			printf("\n");
+		}
+#endif
+
+		if (length)
+		{
+#ifdef DEBUG
+			printf("Received %d bytes\n", length);
+#endif
+			NetReceive((void*)(NetRxPackets[rx_new]),
+			            length - 4);
+		}
+		else
+		{
+#if 1
+			printf("Zero length!!!\n");
+#endif
+		}
+
+		rx_new = (rx_new + 1) % NUM_RX_DESC;
+	}
+
+#ifdef DEBUG
+	printf("Leaving plb2800_eth_recv()\n");
+#endif
+
+	return length;
+}
+
+
+static void plb2800_eth_halt(struct eth_device *dev)
+{
+#ifdef DEBUG
+	printf("Entered plb2800_eth_halt()\n");
+#endif
+
+#ifdef DEBUG
+	printf("Leaving plb2800_eth_halt()\n");
+#endif
+}
+
+static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr)
+{
+	char packet[60];
+	ulong temp;
+	int ix;
+
+	if (mac_addr_set ||
+	    NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)
+	{
+		return;
+	}
+
+	/* send one packet through CPU port
+	 * in order to learn system MAC address
+	 */
+
+	/* Set DA_LOOKUP register */
+	temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);
+	DA_LOOKUP = temp;
+
+	/* Set MA_LEARN register */
+	temp = 50 << MA_DEST_SHF; 	/* static entry */
+	MA_LEARN = temp;
+
+	/* set destination address */
+	for (ix=0;ix<6;ix++)
+		packet[ix] = 0xff;
+
+	/* set source address = system MAC address */
+	for (ix=0;ix<6;ix++)
+		packet[6+ix] = addr[ix];
+
+	/* set type field */
+	packet[12]=0xaa;
+	packet[13]=0x55;
+
+	/* set data field */
+	for(ix=14;ix<60;ix++)
+		packet[ix] = 0x00;
+
+#ifdef DEBUG
+	for (ix=0;ix<6;ix++)
+		printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);
+#endif
+
+	/* set one packet */
+	plb2800_eth_send(dev, packet, sizeof(packet));
+
+	/* delay for a while */
+	for(ix=0;ix<65535;ix++)
+		temp = ~temp;
+
+	/* Set CMAC_CTX_CTRL register */
+	temp = TSTAMP_MS;	/* no autocast */
+	CMAC_CTX_CTRL = temp;
+
+	/* Set DA_LOOKUP register */
+	temp = EN_DA_LKUP;
+	DA_LOOKUP = temp;
+
+	mac_addr_set = 1;
+}
+
+static unsigned char * plb2800_get_mac_addr(void)
+{
+	static unsigned char addr[6];
+	char *tmp, *end;
+	int i;
+
+	tmp = getenv ("ethaddr");
+	if (NULL == tmp) return NULL;
+
+	for (i=0; i<6; i++) {
+		addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+		if (tmp)
+			tmp = (*end) ? end+1 : end;
+	}
+
+	return addr;
+}
+
+#endif /* CONFIG_PLB2800_ETHER */
diff --git a/drivers/net/rtl8019.c b/drivers/net/rtl8019.c
new file mode 100644
index 0000000..409a69f
--- /dev/null
+++ b/drivers/net/rtl8019.c
@@ -0,0 +1,282 @@
+/*
+ * Realtek 8019AS Ethernet
+ * (C) Copyright 2002-2003
+ * Xue Ligong(lgxue@hotmail.com),Wang Kehao, ESLAB, whut.edu.cn
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This code works in 8bit mode.
+ * If you need to work in 16bit mode, PLS change it!
+ */
+
+#include <common.h>
+#include <command.h>
+#include "rtl8019.h"
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_RTL8019
+
+#if defined(CONFIG_CMD_NET)
+
+
+/* packet page register access functions */
+
+
+static unsigned char get_reg (unsigned int regno)
+{
+	return (*(unsigned char *) regno);
+}
+
+
+static void put_reg (unsigned int regno, unsigned char val)
+{
+	*(volatile unsigned char *) regno = val;
+}
+
+static void eth_reset (void)
+{
+	unsigned char ucTemp;
+
+	/* reset NIC */
+	ucTemp = get_reg (RTL8019_RESET);
+	put_reg (RTL8019_RESET, ucTemp);
+	put_reg (RTL8019_INTERRUPTSTATUS, 0xff);
+	udelay (2000);		/* wait for 2ms */
+}
+
+void rtl8019_get_enetaddr (uchar * addr)
+{
+	unsigned char i;
+	unsigned char temp;
+
+	eth_reset ();
+
+	put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);
+	put_reg (RTL8019_DATACONFIGURATION, 0x48);
+	put_reg (RTL8019_REMOTESTARTADDRESS0, 0x00);
+	put_reg (RTL8019_REMOTESTARTADDRESS1, 0x00);
+	put_reg (RTL8019_REMOTEBYTECOUNT0, 12);
+	put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);
+	put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);
+	printf ("MAC: ");
+	for (i = 0; i < 6; i++) {
+		temp = get_reg (RTL8019_DMA_DATA);
+		*addr++ = temp;
+		temp = get_reg (RTL8019_DMA_DATA);
+		printf ("%x:", temp);
+	}
+
+	while ((!get_reg (RTL8019_INTERRUPTSTATUS) & 0x40));
+	printf ("\b \n");
+	put_reg (RTL8019_REMOTEBYTECOUNT0, 0x00);
+	put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0);
+}
+
+
+void eth_halt (void)
+{
+	put_reg (RTL8019_COMMAND, 0x01);
+}
+
+int eth_init (bd_t * bd)
+{
+	eth_reset ();
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);
+	put_reg (RTL8019_DATACONFIGURATION, 0x48);
+	put_reg (RTL8019_REMOTEBYTECOUNT0, 0x00);
+	put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);
+	put_reg (RTL8019_RECEIVECONFIGURATION, 0x00);	/*00; */
+	put_reg (RTL8019_TRANSMITPAGE, RTL8019_TPSTART);
+	put_reg (RTL8019_TRANSMITCONFIGURATION, 0x02);
+	put_reg (RTL8019_PAGESTART, RTL8019_PSTART);
+	put_reg (RTL8019_BOUNDARY, RTL8019_PSTART);
+	put_reg (RTL8019_PAGESTOP, RTL8019_PSTOP);
+	put_reg (RTL8019_INTERRUPTSTATUS, 0xff);
+	put_reg (RTL8019_INTERRUPTMASK, 0x11);	/*b; */
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE1STOP);
+	put_reg (RTL8019_PHYSICALADDRESS0, bd->bi_enetaddr[0]);
+	put_reg (RTL8019_PHYSICALADDRESS1, bd->bi_enetaddr[1]);
+	put_reg (RTL8019_PHYSICALADDRESS2, bd->bi_enetaddr[2]);
+	put_reg (RTL8019_PHYSICALADDRESS3, bd->bi_enetaddr[3]);
+	put_reg (RTL8019_PHYSICALADDRESS4, bd->bi_enetaddr[4]);
+	put_reg (RTL8019_PHYSICALADDRESS5, bd->bi_enetaddr[5]);
+	put_reg (RTL8019_MULTIADDRESS0, 0x00);
+	put_reg (RTL8019_MULTIADDRESS1, 0x00);
+	put_reg (RTL8019_MULTIADDRESS2, 0x00);
+	put_reg (RTL8019_MULTIADDRESS3, 0x00);
+	put_reg (RTL8019_MULTIADDRESS4, 0x00);
+	put_reg (RTL8019_MULTIADDRESS5, 0x00);
+	put_reg (RTL8019_MULTIADDRESS6, 0x00);
+	put_reg (RTL8019_MULTIADDRESS7, 0x00);
+	put_reg (RTL8019_CURRENT, RTL8019_PSTART);
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0);
+	put_reg (RTL8019_TRANSMITCONFIGURATION, 0xe0);	/*58; */
+
+	return 0;
+}
+
+
+static unsigned char nic_to_pc (void)
+{
+	unsigned char rec_head_status;
+	unsigned char next_packet_pointer;
+	unsigned char packet_length0;
+	unsigned char packet_length1;
+	unsigned short rxlen = 0;
+	unsigned int i = 4;
+	unsigned char current_point;
+	unsigned char *addr;
+
+	/*
+	 * The RTL8019's first 4B is packet status,page of next packet
+	 * and packet length(2B).So we receive the fist 4B.
+	 */
+	put_reg (RTL8019_REMOTESTARTADDRESS1, get_reg (RTL8019_BOUNDARY));
+	put_reg (RTL8019_REMOTESTARTADDRESS0, 0x00);
+	put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);
+	put_reg (RTL8019_REMOTEBYTECOUNT0, 0x04);
+
+	put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);
+
+	rec_head_status = get_reg (RTL8019_DMA_DATA);
+	next_packet_pointer = get_reg (RTL8019_DMA_DATA);
+	packet_length0 = get_reg (RTL8019_DMA_DATA);
+	packet_length1 = get_reg (RTL8019_DMA_DATA);
+
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0);
+	/*Packet length is in two 8bit registers */
+	rxlen = packet_length1;
+	rxlen = (((rxlen << 8) & 0xff00) + packet_length0);
+	rxlen -= 4;
+
+	if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
+		printf ("packet too big!\n");
+
+	/*Receive the packet */
+	put_reg (RTL8019_REMOTESTARTADDRESS0, 0x04);
+	put_reg (RTL8019_REMOTESTARTADDRESS1, get_reg (RTL8019_BOUNDARY));
+
+	put_reg (RTL8019_REMOTEBYTECOUNT0, (rxlen & 0xff));
+	put_reg (RTL8019_REMOTEBYTECOUNT1, ((rxlen >> 8) & 0xff));
+
+
+	put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);
+
+	for (addr = (unsigned char *) NetRxPackets[0], i = rxlen; i > 0; i--)
+		*addr++ = get_reg (RTL8019_DMA_DATA);
+	/* Pass the packet up to the protocol layers. */
+	NetReceive (NetRxPackets[0], rxlen);
+
+	while (!(get_reg (RTL8019_INTERRUPTSTATUS)) & 0x40);	/* wait for the op. */
+
+	/*
+	 * To test whether the packets are all received,get the
+	 * location of current point
+	 */
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE1);
+	current_point = get_reg (RTL8019_CURRENT);
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0);
+	put_reg (RTL8019_BOUNDARY, next_packet_pointer);
+	return current_point;
+}
+
+/* Get a data block via Ethernet */
+extern int eth_rx (void)
+{
+	unsigned char temp, current_point;
+
+	put_reg (RTL8019_COMMAND, RTL8019_PAGE0);
+
+	while (1) {
+		temp = get_reg (RTL8019_INTERRUPTSTATUS);
+
+		if (temp & 0x90) {
+			/*overflow */
+			put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);
+			udelay (2000);
+			put_reg (RTL8019_REMOTEBYTECOUNT0, 0);
+			put_reg (RTL8019_REMOTEBYTECOUNT1, 0);
+			put_reg (RTL8019_TRANSMITCONFIGURATION, 2);
+			do {
+				current_point = nic_to_pc ();
+			} while (get_reg (RTL8019_BOUNDARY) != current_point);
+
+			put_reg (RTL8019_TRANSMITCONFIGURATION, 0xe0);
+		}
+
+		if (temp & 0x1) {
+			/*packet received */
+			do {
+				put_reg (RTL8019_INTERRUPTSTATUS, 0x01);
+				current_point = nic_to_pc ();
+			} while (get_reg (RTL8019_BOUNDARY) != current_point);
+		}
+
+		if (!(temp & 0x1))
+			return 0;
+		/* done and exit. */
+	}
+}
+
+/* Send a data block via Ethernet. */
+extern int eth_send (volatile void *packet, int length)
+{
+	volatile unsigned char *p;
+	unsigned int pn;
+
+	pn = length;
+	p = (volatile unsigned char *) packet;
+
+	while (get_reg (RTL8019_COMMAND) == RTL8019_TRANSMIT);
+
+	put_reg (RTL8019_REMOTESTARTADDRESS0, 0);
+	put_reg (RTL8019_REMOTESTARTADDRESS1, RTL8019_TPSTART);
+	put_reg (RTL8019_REMOTEBYTECOUNT0, (pn & 0xff));
+	put_reg (RTL8019_REMOTEBYTECOUNT1, ((pn >> 8) & 0xff));
+
+	put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMAWR);
+	while (pn > 0) {
+		put_reg (RTL8019_DMA_DATA, *p++);
+		pn--;
+	}
+
+	pn = length;
+
+	while (pn < 60) {	/*Padding */
+		put_reg (RTL8019_DMA_DATA, 0);
+		pn++;
+	}
+
+	while (!(get_reg (RTL8019_INTERRUPTSTATUS)) & 0x40);
+
+	put_reg (RTL8019_INTERRUPTSTATUS, 0x40);
+	put_reg (RTL8019_TRANSMITPAGE, RTL8019_TPSTART);
+	put_reg (RTL8019_TRANSMITBYTECOUNT0, (pn & 0xff));
+	put_reg (RTL8019_TRANSMITBYTECOUNT1, ((pn >> 8 & 0xff)));
+	put_reg (RTL8019_COMMAND, RTL8019_TRANSMIT);
+
+	return 0;
+}
+
+#endif /* COMMANDS & CFG_NET */
+
+#endif /* CONFIG_DRIVER_RTL8019 */
diff --git a/drivers/net/rtl8019.h b/drivers/net/rtl8019.h
new file mode 100644
index 0000000..38116ad
--- /dev/null
+++ b/drivers/net/rtl8019.h
@@ -0,0 +1,117 @@
+/*
+ * Realtek 8019AS Ethernet
+ * (C) Copyright 2002-2003
+ * Xue Ligong(lgxue@hotmail.com),Wang Kehao, ESLAB, whut.edu.cn
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This code works in 8bit mode.
+ * If you need to work in 16bit mode, PLS change it!
+ */
+
+#include <asm/types.h>
+#include <config.h>
+
+
+#ifdef CONFIG_DRIVER_RTL8019
+
+#define		RTL8019_REG_00        		(RTL8019_BASE + 0x00)
+#define 	RTL8019_REG_01        		(RTL8019_BASE + 0x01)
+#define 	RTL8019_REG_02        		(RTL8019_BASE + 0x02)
+#define 	RTL8019_REG_03        		(RTL8019_BASE + 0x03)
+#define 	RTL8019_REG_04        		(RTL8019_BASE + 0x04)
+#define 	RTL8019_REG_05        		(RTL8019_BASE + 0x05)
+#define 	RTL8019_REG_06        		(RTL8019_BASE + 0x06)
+#define 	RTL8019_REG_07        		(RTL8019_BASE + 0x07)
+#define 	RTL8019_REG_08        		(RTL8019_BASE + 0x08)
+#define 	RTL8019_REG_09        		(RTL8019_BASE + 0x09)
+#define 	RTL8019_REG_0a        		(RTL8019_BASE + 0x0a)
+#define 	RTL8019_REG_0b        		(RTL8019_BASE + 0x0b)
+#define 	RTL8019_REG_0c        		(RTL8019_BASE + 0x0c)
+#define 	RTL8019_REG_0d        		(RTL8019_BASE + 0x0d)
+#define 	RTL8019_REG_0e       	 	(RTL8019_BASE + 0x0e)
+#define 	RTL8019_REG_0f        		(RTL8019_BASE + 0x0f)
+#define 	RTL8019_REG_10        		(RTL8019_BASE + 0x10)
+#define 	RTL8019_REG_1f        		(RTL8019_BASE + 0x1f)
+
+#define		RTL8019_COMMAND			RTL8019_REG_00
+#define		RTL8019_PAGESTART		RTL8019_REG_01
+#define		RTL8019_PAGESTOP		RTL8019_REG_02
+#define		RTL8019_BOUNDARY		RTL8019_REG_03
+#define		RTL8019_TRANSMITSTATUS		RTL8019_REG_04
+#define		RTL8019_TRANSMITPAGE		RTL8019_REG_04
+#define		RTL8019_TRANSMITBYTECOUNT0	RTL8019_REG_05
+#define		RTL8019_NCR 			RTL8019_REG_05
+#define		RTL8019_TRANSMITBYTECOUNT1 	RTL8019_REG_06
+#define		RTL8019_INTERRUPTSTATUS		RTL8019_REG_07
+#define		RTL8019_CURRENT 		RTL8019_REG_07
+#define		RTL8019_REMOTESTARTADDRESS0 	RTL8019_REG_08
+#define		RTL8019_CRDMA0  		RTL8019_REG_08
+#define		RTL8019_REMOTESTARTADDRESS1 	RTL8019_REG_09
+#define		RTL8019_CRDMA1 			RTL8019_REG_09
+#define		RTL8019_REMOTEBYTECOUNT0	RTL8019_REG_0a
+#define		RTL8019_REMOTEBYTECOUNT1	RTL8019_REG_0b
+#define		RTL8019_RECEIVESTATUS		RTL8019_REG_0c
+#define		RTL8019_RECEIVECONFIGURATION	RTL8019_REG_0c
+#define		RTL8019_TRANSMITCONFIGURATION	RTL8019_REG_0d
+#define		RTL8019_FAE_TALLY 		RTL8019_REG_0d
+#define		RTL8019_DATACONFIGURATION	RTL8019_REG_0e
+#define		RTL8019_CRC_TALLY 		RTL8019_REG_0e
+#define		RTL8019_INTERRUPTMASK		RTL8019_REG_0f
+#define		RTL8019_MISS_PKT_TALLY		RTL8019_REG_0f
+#define		RTL8019_PHYSICALADDRESS0	RTL8019_REG_01
+#define 	RTL8019_PHYSICALADDRESS1	RTL8019_REG_02
+#define		RTL8019_PHYSICALADDRESS2	RTL8019_REG_03
+#define		RTL8019_PHYSICALADDRESS3	RTL8019_REG_04
+#define		RTL8019_PHYSICALADDRESS4	RTL8019_REG_05
+#define		RTL8019_PHYSICALADDRESS5	RTL8019_REG_06
+#define		RTL8019_MULTIADDRESS0		RTL8019_REG_08
+#define		RTL8019_MULTIADDRESS1		RTL8019_REG_09
+#define		RTL8019_MULTIADDRESS2		RTL8019_REG_0a
+#define		RTL8019_MULTIADDRESS3		RTL8019_REG_0b
+#define		RTL8019_MULTIADDRESS4		RTL8019_REG_0c
+#define		RTL8019_MULTIADDRESS5		RTL8019_REG_0d
+#define		RTL8019_MULTIADDRESS6		RTL8019_REG_0e
+#define		RTL8019_MULTIADDRESS7		RTL8019_REG_0f
+#define		RTL8019_DMA_DATA		RTL8019_REG_10
+#define		RTL8019_RESET			RTL8019_REG_1f
+
+
+#define 	RTL8019_PAGE0               	0x22
+#define   	RTL8019_PAGE1               	0x62
+#define   	RTL8019_PAGE0DMAWRITE       	0x12
+#define   	RTL8019_PAGE2DMAWRITE       	0x92
+#define   	RTL8019_REMOTEDMAWR         	0x12
+#define   	RTL8019_REMOTEDMARD         	0x0A
+#define   	RTL8019_ABORTDMAWR          	0x32
+#define   	RTL8019_ABORTDMARD          	0x2A
+#define   	RTL8019_PAGE0STOP           	0x21
+#define   	RTL8019_PAGE1STOP           	0x61
+#define   	RTL8019_TRANSMIT            	0x26
+#define   	RTL8019_TXINPROGRESS        	0x04
+#define   	RTL8019_SEND		    	0x1A
+
+#define		RTL8019_PSTART			0x4c
+#define		RTL8019_PSTOP			0x80
+#define		RTL8019_TPSTART			0x40
+
+
+#endif /*end of CONFIG_DRIVER_RTL8019*/
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
new file mode 100644
index 0000000..2367180
--- /dev/null
+++ b/drivers/net/rtl8139.c
@@ -0,0 +1,547 @@
+/*
+ * rtl8139.c : U-Boot driver for the RealTek RTL8139
+ *
+ * Masami Komiya (mkomiya@sonare.it)
+ *
+ * Most part is taken from rtl8139.c of etherboot
+ *
+ */
+
+/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
+
+  ported from the linux driver written by Donald Becker
+  by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
+
+  This software may be used and distributed according to the terms
+  of the GNU Public License, incorporated herein by reference.
+
+  changes to the original driver:
+  - removed support for interrupts, switching to polling mode (yuck!)
+  - removed support for the 8129 chip (external MII)
+
+*/
+
+/*********************************************************************/
+/* Revision History						     */
+/*********************************************************************/
+
+/*
+  28 Dec 2002	ken_yap@users.sourceforge.net (Ken Yap)
+     Put in virt_to_bus calls to allow Etherboot relocation.
+
+  06 Apr 2001	ken_yap@users.sourceforge.net (Ken Yap)
+     Following email from Hyun-Joon Cha, added a disable routine, otherwise
+     NIC remains live and can crash the kernel later.
+
+  4 Feb 2000	espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
+     Shuffled things around, removed the leftovers from the 8129 support
+     that was in the Linux driver and added a bit more 8139 definitions.
+     Moved the 8K receive buffer to a fixed, available address outside the
+     0x98000-0x9ffff range.  This is a bit of a hack, but currently the only
+     way to make room for the Etherboot features that need substantial amounts
+     of code like the ANSI console support.  Currently the buffer is just below
+     0x10000, so this even conforms to the tagged boot image specification,
+     which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000.  My
+     interpretation of this "reserved" is that Etherboot may do whatever it
+     likes, as long as its environment is kept intact (like the BIOS
+     variables).  Hopefully fixed rtl_poll() once and for all.	The symptoms
+     were that if Etherboot was left at the boot menu for several minutes, the
+     first eth_poll failed.  Seems like I am the only person who does this.
+     First of all I fixed the debugging code and then set out for a long bug
+     hunting session.  It took me about a week full time work - poking around
+     various places in the driver, reading Don Becker's and Jeff Garzik's Linux
+     driver and even the FreeBSD driver (what a piece of crap!) - and
+     eventually spotted the nasty thing: the transmit routine was acknowledging
+     each and every interrupt pending, including the RxOverrun and RxFIFIOver
+     interrupts.  This confused the RTL8139 thoroughly.	 It destroyed the
+     Rx ring contents by dumping the 2K FIFO contents right where we wanted to
+     get the next packet.  Oh well, what fun.
+
+  18 Jan 2000	mdc@thinguin.org (Marty Connor)
+     Drastically simplified error handling.  Basically, if any error
+     in transmission or reception occurs, the card is reset.
+     Also, pointed all transmit descriptors to the same buffer to
+     save buffer space.	 This should decrease driver size and avoid
+     corruption because of exceeding 32K during runtime.
+
+  28 Jul 1999	(Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
+     rtl_poll was quite broken: it used the RxOK interrupt flag instead
+     of the RxBufferEmpty flag which often resulted in very bad
+     transmission performace - below 1kBytes/s.
+
+*/
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+	defined(CONFIG_RTL8139)
+
+#define TICKS_PER_SEC	CFG_HZ
+#define TICKS_PER_MS	(TICKS_PER_SEC/1000)
+
+#define RTL_TIMEOUT	(1*TICKS_PER_SEC)
+
+#define ETH_FRAME_LEN		1514
+#define ETH_ALEN		6
+#define ETH_ZLEN		60
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+#define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4	/* Calculate as 16<<val. */
+#define NUM_TX_DESC	4	/* Number of Tx descriptor registers. */
+#define TX_BUF_SIZE	ETH_FRAME_LEN	/* FCS is added by the chip */
+#define RX_BUF_LEN_IDX 0	/* 0, 1, 2 is allowed - 8,16,32K rx buffer */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+#undef DEBUG_TX
+#undef DEBUG_RX
+
+#define currticks()	get_timer(0)
+#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+	MAC0=0,			/* Ethernet hardware address. */
+	MAR0=8,			/* Multicast filter. */
+	TxStatus0=0x10,		/* Transmit status (four 32bit registers). */
+	TxAddr0=0x20,		/* Tx descriptors (also four 32bit). */
+	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+	IntrMask=0x3C, IntrStatus=0x3E,
+	TxConfig=0x40, RxConfig=0x44,
+	Timer=0x48,		/* general-purpose counter. */
+	RxMissed=0x4C,		/* 24 bits valid, write clears. */
+	Cfg9346=0x50, Config0=0x51, Config1=0x52,
+	TimerIntrReg=0x54,	/* intr if gp counter reaches this value */
+	MediaStatus=0x58,
+	Config3=0x59,
+	MultiIntr=0x5C,
+	RevisionID=0x5E,	/* revision of the RTL8139 chip */
+	TxSummary=0x60,
+	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
+	NWayExpansion=0x6A,
+	DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
+	NWayTestReg=0x70,
+	RxCnt=0x72,		/* packet received counter */
+	CSCR=0x74,		/* chip status and configuration register */
+	PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80,	/* undocumented */
+	/* from 0x84 onwards are a number of power management/wakeup frame
+	 * definitions we will probably never need to know about.  */
+};
+
+enum ChipCmdBits {
+	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
+	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+	TxOutOfWindow=0x20000000, TxAborted=0x40000000,
+	TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+	RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+enum MediaStatusBits {
+	MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
+	MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
+};
+
+enum MIIBMCRBits {
+	BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
+	BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
+};
+
+enum CSCRBits {
+	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+	CSCR_LinkDownCmd=0x0f3c0,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+	RxCfgWrap=0x80,
+	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+
+static int ioaddr;
+static unsigned int cur_rx,cur_tx;
+
+/* The RTL8139 can only transmit from a contiguous, aligned memory block.  */
+static unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4)));
+static unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4)));
+
+static int rtl8139_probe(struct eth_device *dev, bd_t *bis);
+static int read_eeprom(int location, int addr_len);
+static void rtl_reset(struct eth_device *dev);
+static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length);
+static int rtl_poll(struct eth_device *dev);
+static void rtl_disable(struct eth_device *dev);
+#ifdef CONFIG_MCAST_TFTP/*  This driver already accepts all b/mcast */
+static int rtl_bcast_addr (struct eth_device *dev, u8 bcast_mac, u8 set)
+{
+	return (0);
+}
+#endif
+
+static struct pci_device_id supported[] = {
+       {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139},
+       {PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139},
+       {}
+};
+
+int rtl8139_initialize(bd_t *bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	u32 iobase;
+	int idx=0;
+
+	while(1){
+		/* Find RTL8139 */
+		if ((devno = pci_find_devices(supported, idx++)) < 0)
+			break;
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+		iobase &= ~0xf;
+
+		debug ("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
+
+		dev = (struct eth_device *)malloc(sizeof *dev);
+
+		sprintf (dev->name, "RTL8139#%d", card_number);
+
+		dev->priv = (void *) devno;
+		dev->iobase = (int)bus_to_phys(iobase);
+		dev->init = rtl8139_probe;
+		dev->halt = rtl_disable;
+		dev->send = rtl_transmit;
+		dev->recv = rtl_poll;
+#ifdef CONFIG_MCAST_TFTP
+		dev->mcast = rtl_bcast_addr;
+#endif
+
+		eth_register (dev);
+
+		card_number++;
+
+		pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
+
+		udelay (10 * 1000);
+	}
+
+	return card_number;
+}
+
+static int rtl8139_probe(struct eth_device *dev, bd_t *bis)
+{
+	int i;
+	int speed10, fullduplex;
+	int addr_len;
+	unsigned short *ap = (unsigned short *)dev->enetaddr;
+
+	ioaddr = dev->iobase;
+
+	/* Bring the chip out of low-power mode. */
+	outb(0x00, ioaddr + Config1);
+
+	addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6;
+	for (i = 0; i < 3; i++)
+		*ap++ = le16_to_cpu (read_eeprom(i + 7, addr_len));
+
+	speed10 = inb(ioaddr + MediaStatus) & MSRSpeed10;
+	fullduplex = inw(ioaddr + MII_BMCR) & BMCRDuplex;
+
+	rtl_reset(dev);
+
+	if (inb(ioaddr + MediaStatus) & MSRLinkFail) {
+		printf("Cable not connected or other link failure\n");
+		return(0);
+	}
+
+	return 1;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS		0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0	0x00
+#define EE_WRITE_1	0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB		(0x80 | EE_CS)
+
+/*
+	Delay between EEPROM clock transitions.
+	No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+*/
+
+#define eeprom_delay()	inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5)
+#define EE_READ_CMD	(6)
+#define EE_ERASE_CMD	(7)
+
+static int read_eeprom(int location, int addr_len)
+{
+	int i;
+	unsigned int retval = 0;
+	long ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	outb(EE_ENB & ~EE_CS, ee_addr);
+	outb(EE_ENB, ee_addr);
+	eeprom_delay();
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outb(EE_ENB | dataval, ee_addr);
+		eeprom_delay();
+		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+	}
+	outb(EE_ENB, ee_addr);
+	eeprom_delay();
+
+	for (i = 16; i > 0; i--) {
+		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outb(EE_ENB, ee_addr);
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	outb(~EE_CS, ee_addr);
+	eeprom_delay();
+	return retval;
+}
+
+static const unsigned int rtl8139_rx_config =
+	(RX_BUF_LEN_IDX << 11) |
+	(RX_FIFO_THRESH << 13) |
+	(RX_DMA_BURST << 8);
+
+static void set_rx_mode(struct eth_device *dev) {
+	unsigned int mc_filter[2];
+	int rx_mode;
+	/* !IFF_PROMISC */
+	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+	outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig);
+
+	outl(mc_filter[0], ioaddr + MAR0 + 0);
+	outl(mc_filter[1], ioaddr + MAR0 + 4);
+}
+
+static void rtl_reset(struct eth_device *dev)
+{
+	int i;
+
+	outb(CmdReset, ioaddr + ChipCmd);
+
+	cur_rx = 0;
+	cur_tx = 0;
+
+	/* Give the chip 10ms to finish the reset. */
+	for (i=0; i<100; ++i){
+		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
+		udelay (100); /* wait 100us */
+	}
+
+
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(dev->enetaddr[i], ioaddr + MAC0 + i);
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+	outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
+		ioaddr + RxConfig);		/* accept no frames yet!  */
+	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+
+	/* The Linux driver changes Config1 here to use a different LED pattern
+	 * for half duplex or full/autodetect duplex (for full/autodetect, the
+	 * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
+	 * TX/RX, Link100, Link10).  This is messy, because it doesn't match
+	 * the inscription on the mounting bracket.  It should not be changed
+	 * from the configuration EEPROM default, because the card manufacturer
+	 * should have set that to match the card.  */
+
+#ifdef	DEBUG_RX
+	printf("rx ring address is %X\n",(unsigned long)rx_ring);
+#endif
+	outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
+
+	/* If we add multicast support, the MAR0 register would have to be
+	 * initialized to 0xffffffffffffffff (two 32 bit accesses).  Etherboot
+	 * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast.	*/
+
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+
+	outl(rtl8139_rx_config, ioaddr + RxConfig);
+
+	/* Start the chip's Tx and Rx process. */
+	outl(0, ioaddr + RxMissed);
+
+	/* set_rx_mode */
+	set_rx_mode(dev);
+
+	/* Disable all known interrupts by setting the interrupt mask. */
+	outw(0, ioaddr + IntrMask);
+}
+
+static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length)
+{
+	unsigned int status, to;
+	unsigned long txstatus;
+	unsigned int len = length;
+
+	ioaddr = dev->iobase;
+
+	memcpy((char *)tx_buffer, (char *)packet, (int)length);
+
+#ifdef	DEBUG_TX
+	printf("sending %d bytes\n", len);
+#endif
+
+	/* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
+	 * bytes are sent automatically for the FCS, totalling to 64 bytes). */
+	while (len < ETH_ZLEN) {
+		tx_buffer[len++] = '\0';
+	}
+
+	outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
+	outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
+		ioaddr + TxStatus0 + cur_tx*4);
+
+	to = currticks() + RTL_TIMEOUT;
+
+	do {
+		status = inw(ioaddr + IntrStatus);
+		/* Only acknlowledge interrupt sources we can properly handle
+		 * here - the RxOverflow/RxFIFOOver MUST be handled in the
+		 * rtl_poll() function.	 */
+		outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
+		if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
+	} while (currticks() < to);
+
+	txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
+
+	if (status & TxOK) {
+		cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+#ifdef	DEBUG_TX
+		printf("tx done (%d ticks), status %hX txstatus %X\n",
+			to-currticks(), status, txstatus);
+#endif
+		return length;
+	} else {
+#ifdef	DEBUG_TX
+		printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",
+			currticks()-to, status, txstatus);
+#endif
+		rtl_reset(dev);
+
+		return 0;
+	}
+}
+
+static int rtl_poll(struct eth_device *dev)
+{
+	unsigned int status;
+	unsigned int ring_offs;
+	unsigned int rx_size, rx_status;
+	int length=0;
+
+	ioaddr = dev->iobase;
+
+	if (inb(ioaddr + ChipCmd) & RxBufEmpty) {
+		return 0;
+	}
+
+	status = inw(ioaddr + IntrStatus);
+	/* See below for the rest of the interrupt acknowledges.  */
+	outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+
+#ifdef	DEBUG_RX
+	printf("rtl_poll: int %hX ", status);
+#endif
+
+	ring_offs = cur_rx % RX_BUF_LEN;
+	rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs));
+	rx_size = rx_status >> 16;
+	rx_status &= 0xffff;
+
+	if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) ||
+	    (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {
+		printf("rx error %hX\n", rx_status);
+		rtl_reset(dev); /* this clears all interrupts still pending */
+		return 0;
+	}
+
+	/* Received a good packet */
+	length = rx_size - 4;	/* no one cares about the FCS */
+	if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {
+		int semi_count = RX_BUF_LEN - ring_offs - 4;
+		unsigned char rxdata[RX_BUF_LEN];
+
+		memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
+		memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);
+
+		NetReceive(rxdata, length);
+#ifdef	DEBUG_RX
+		printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count);
+#endif
+	} else {
+		NetReceive(rx_ring + ring_offs + 4, length);
+#ifdef	DEBUG_RX
+		printf("rx packet %d bytes", rx_size-4);
+#endif
+	}
+
+	cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+	outw(cur_rx - 16, ioaddr + RxBufPtr);
+	/* See RTL8139 Programming Guide V0.1 for the official handling of
+	 * Rx overflow situations.  The document itself contains basically no
+	 * usable information, except for a few exception handling rules.  */
+	outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+	return length;
+}
+
+static void rtl_disable(struct eth_device *dev)
+{
+	int i;
+
+	ioaddr = dev->iobase;
+
+	/* reset the chip */
+	outb(CmdReset, ioaddr + ChipCmd);
+
+	/* Give the chip 10ms to finish the reset. */
+	for (i=0; i<100; ++i){
+		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
+		udelay (100); /* wait 100us */
+	}
+}
+#endif
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
new file mode 100644
index 0000000..63ea2cc
--- /dev/null
+++ b/drivers/net/rtl8169.c
@@ -0,0 +1,888 @@
+/*
+ * rtl8169.c : U-Boot driver for the RealTek RTL8169
+ *
+ * Masami Komiya (mkomiya@sonare.it)
+ *
+ * Most part is taken from r8169.c of etherboot
+ *
+ */
+
+/**************************************************************************
+*    r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
+*    Written 2003 by Timothy Legge <tlegge@rogers.com>
+*
+*    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.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*	r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
+*		for Linux kernel 2.4.x.
+*
+*    Written 2002 ShuChen <shuchen@realtek.com.tw>
+*	  See Linux Driver for full information
+*
+*    Linux Driver Version 1.27a, 10.02.2002
+*
+*    Thanks to:
+*	Jean Chen of RealTek Semiconductor Corp. for
+*	providing the evaluation NIC used to develop
+*	this driver.  RealTek's support for Etherboot
+*	is appreciated.
+*
+*    REVISION HISTORY:
+*    ================
+*
+*    v1.0	11-26-2003	timlegge	Initial port of Linux driver
+*    v1.5	01-17-2004	timlegge	Initial driver output cleanup
+*
+*    Indent Options: indent -kr -i8
+***************************************************************************/
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+	defined(CONFIG_RTL8169)
+
+#undef DEBUG_RTL8169
+#undef DEBUG_RTL8169_TX
+#undef DEBUG_RTL8169_RX
+
+#define drv_version "v1.5"
+#define drv_date "01-17-2004"
+
+static u32 ioaddr;
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)	cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)	bus_to_virt(le32_to_cpu(addr))
+
+#define currticks()	get_timer(0)
+#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+
+/* MAC address length*/
+#define MAC_ADDR_LEN	6
+
+/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
+#define TX_FIFO_THRESH 256	/* In bytes */
+
+#define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer.	 */
+#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld	0x3F	/* 0x3F means NO early transmit */
+#define RxPacketMaxSize 0x0800	/* Maximum size supported is 16K-1 */
+#define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
+
+#define NUM_TX_DESC	1	/* Number of Tx descriptor registers */
+#define NUM_RX_DESC	4	/* Number of Rx descriptor registers */
+#define RX_BUF_SIZE	1536	/* Rx Buffer size */
+#define RX_BUF_LEN	8192
+
+#define RTL_MIN_IO_SIZE 0x80
+#define TX_TIMEOUT  (6*HZ)
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg)		readb (ioaddr + (reg))
+#define RTL_R16(reg)		readw (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+
+#define ETH_FRAME_LEN	MAX_ETH_FRAME_SIZE
+#define ETH_ALEN	MAC_ADDR_LEN
+#define ETH_ZLEN	60
+
+enum RTL8169_registers {
+	MAC0 = 0,		/* Ethernet hardware address. */
+	MAR0 = 8,		/* Multicast filter. */
+	TxDescStartAddr = 0x20,
+	TxHDescStartAddr = 0x28,
+	FLASH = 0x30,
+	ERSR = 0x36,
+	ChipCmd = 0x37,
+	TxPoll = 0x38,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	TxConfig = 0x40,
+	RxConfig = 0x44,
+	RxMissed = 0x4C,
+	Cfg9346 = 0x50,
+	Config0 = 0x51,
+	Config1 = 0x52,
+	Config2 = 0x53,
+	Config3 = 0x54,
+	Config4 = 0x55,
+	Config5 = 0x56,
+	MultiIntr = 0x5C,
+	PHYAR = 0x60,
+	TBICSR = 0x64,
+	TBI_ANAR = 0x68,
+	TBI_LPAR = 0x6A,
+	PHYstatus = 0x6C,
+	RxMaxSize = 0xDA,
+	CPlusCmd = 0xE0,
+	RxDescStartAddr = 0xE4,
+	EarlyTxThres = 0xEC,
+	FuncEvent = 0xF0,
+	FuncEventMask = 0xF4,
+	FuncPresetState = 0xF8,
+	FuncForceEvent = 0xFC,
+};
+
+enum RTL8169_register_content {
+	/*InterruptStatusBits */
+	SYSErr = 0x8000,
+	PCSTimeout = 0x4000,
+	SWInt = 0x0100,
+	TxDescUnavail = 0x80,
+	RxFIFOOver = 0x40,
+	RxUnderrun = 0x20,
+	RxOverflow = 0x10,
+	TxErr = 0x08,
+	TxOK = 0x04,
+	RxErr = 0x02,
+	RxOK = 0x01,
+
+	/*RxStatusDesc */
+	RxRES = 0x00200000,
+	RxCRC = 0x00080000,
+	RxRUNT = 0x00100000,
+	RxRWT = 0x00400000,
+
+	/*ChipCmdBits */
+	CmdReset = 0x10,
+	CmdRxEnb = 0x08,
+	CmdTxEnb = 0x04,
+	RxBufEmpty = 0x01,
+
+	/*Cfg9346Bits */
+	Cfg9346_Lock = 0x00,
+	Cfg9346_Unlock = 0xC0,
+
+	/*rx_mode_bits */
+	AcceptErr = 0x20,
+	AcceptRunt = 0x10,
+	AcceptBroadcast = 0x08,
+	AcceptMulticast = 0x04,
+	AcceptMyPhys = 0x02,
+	AcceptAllPhys = 0x01,
+
+	/*RxConfigBits */
+	RxCfgFIFOShift = 13,
+	RxCfgDMAShift = 8,
+
+	/*TxConfigBits */
+	TxInterFrameGapShift = 24,
+	TxDMAShift = 8,		/* DMA burst value (0-7) is shift this many bits */
+
+	/*rtl8169_PHYstatus */
+	TBI_Enable = 0x80,
+	TxFlowCtrl = 0x40,
+	RxFlowCtrl = 0x20,
+	_1000bpsF = 0x10,
+	_100bps = 0x08,
+	_10bps = 0x04,
+	LinkStatus = 0x02,
+	FullDup = 0x01,
+
+	/*GIGABIT_PHY_registers */
+	PHY_CTRL_REG = 0,
+	PHY_STAT_REG = 1,
+	PHY_AUTO_NEGO_REG = 4,
+	PHY_1000_CTRL_REG = 9,
+
+	/*GIGABIT_PHY_REG_BIT */
+	PHY_Restart_Auto_Nego = 0x0200,
+	PHY_Enable_Auto_Nego = 0x1000,
+
+	/* PHY_STAT_REG = 1; */
+	PHY_Auto_Neco_Comp = 0x0020,
+
+	/* PHY_AUTO_NEGO_REG = 4; */
+	PHY_Cap_10_Half = 0x0020,
+	PHY_Cap_10_Full = 0x0040,
+	PHY_Cap_100_Half = 0x0080,
+	PHY_Cap_100_Full = 0x0100,
+
+	/* PHY_1000_CTRL_REG = 9; */
+	PHY_Cap_1000_Full = 0x0200,
+
+	PHY_Cap_Null = 0x0,
+
+	/*_MediaType*/
+	_10_Half = 0x01,
+	_10_Full = 0x02,
+	_100_Half = 0x04,
+	_100_Full = 0x08,
+	_1000_Full = 0x10,
+
+	/*_TBICSRBit*/
+	TBILinkOK = 0x02000000,
+};
+
+static struct {
+	const char *name;
+	u8 version;		/* depend on RTL8169 docs */
+	u32 RxConfigMask;	/* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+	{"RTL-8169", 0x00, 0xff7e1880,},
+	{"RTL-8169", 0x04, 0xff7e1880,},
+};
+
+enum _DescStatusBit {
+	OWNbit = 0x80000000,
+	EORbit = 0x40000000,
+	FSbit = 0x20000000,
+	LSbit = 0x10000000,
+};
+
+struct TxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+struct RxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+/* Define the TX Descriptor */
+static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
+/*	__attribute__ ((aligned(256))); */
+
+/* Create a static buffer of size RX_BUF_SZ for each
+TX Descriptor.	All descriptors point to a
+part of this buffer */
+static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
+
+/* Define the RX Descriptor */
+static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
+  /*  __attribute__ ((aligned(256))); */
+
+/* Create a static buffer of size RX_BUF_SZ for each
+RX Descriptor	All descriptors point to a
+part of this buffer */
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
+
+struct rtl8169_private {
+	void *mmio_addr;	/* memory map physical address */
+	int chipset;
+	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
+	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
+	unsigned long dirty_tx;
+	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
+	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
+	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
+	unsigned char *RxBufferRings;	/* Index of Rx Buffer  */
+	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
+	unsigned char *Tx_skbuff[NUM_TX_DESC];
+} tpx;
+
+static struct rtl8169_private *tpc;
+
+static const u16 rtl8169_intr_mask =
+    SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr |
+    TxOK | RxErr | RxOK;
+static const unsigned int rtl8169_rx_config =
+    (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_REALTEK, 0x8169},
+	{}
+};
+
+void mdio_write(int RegAddr, int value)
+{
+	int i;
+
+	RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		/* Check if the RTL8169 has completed writing to the specified MII register */
+		if (!(RTL_R32(PHYAR) & 0x80000000)) {
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+}
+
+int mdio_read(int RegAddr)
+{
+	int i, value = -1;
+
+	RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		/* Check if the RTL8169 has completed retrieving data from the specified MII register */
+		if (RTL_R32(PHYAR) & 0x80000000) {
+			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+	return value;
+}
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static int rtl8169_init_board(struct eth_device *dev)
+{
+	int i;
+	u32 tmp;
+
+#ifdef DEBUG_RTL8169
+	printf ("%s\n", __FUNCTION__);
+#endif
+	ioaddr = dev->iobase;
+
+	/* Soft reset the chip. */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+
+	/* identify chip attached to board */
+	tmp = RTL_R32(TxConfig);
+	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
+
+	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--){
+		if (tmp == rtl_chip_info[i].version) {
+			tpc->chipset = i;
+			goto match;
+		}
+	}
+
+	/* if unknown chip, assume array element #0, original RTL-8169 in this case */
+	printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name);
+	printf("PCI device: TxConfig = 0x%hX\n", (unsigned long) RTL_R32(TxConfig));
+	tpc->chipset = 0;
+
+match:
+	return 0;
+}
+
+/**************************************************************************
+RECV - Receive a frame
+***************************************************************************/
+static int rtl_recv(struct eth_device *dev)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+	int cur_rx;
+	int length = 0;
+
+#ifdef DEBUG_RTL8169_RX
+	printf ("%s\n", __FUNCTION__);
+#endif
+	ioaddr = dev->iobase;
+
+	cur_rx = tpc->cur_rx;
+	if ((tpc->RxDescArray[cur_rx].status & OWNbit) == 0) {
+		if (!(tpc->RxDescArray[cur_rx].status & RxRES)) {
+			unsigned char rxdata[RX_BUF_LEN];
+			length = (int) (tpc->RxDescArray[cur_rx].
+						status & 0x00001FFF) - 4;
+
+			memcpy(rxdata, tpc->RxBufferRing[cur_rx], length);
+			NetReceive(rxdata, length);
+
+			if (cur_rx == NUM_RX_DESC - 1)
+				tpc->RxDescArray[cur_rx].status =
+				    (OWNbit | EORbit) + RX_BUF_SIZE;
+			else
+				tpc->RxDescArray[cur_rx].status =
+				    OWNbit + RX_BUF_SIZE;
+			tpc->RxDescArray[cur_rx].buf_addr =
+			    virt_to_bus(tpc->RxBufferRing[cur_rx]);
+		} else {
+			puts("Error Rx");
+		}
+		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
+		tpc->cur_rx = cur_rx;
+		return 1;
+
+	}
+	tpc->cur_rx = cur_rx;
+	return (0);		/* initially as this is called to flush the input */
+}
+
+#define HZ 1000
+/**************************************************************************
+SEND - Transmit a frame
+***************************************************************************/
+static int rtl_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	/* send the packet to destination */
+
+	u32 to;
+	u8 *ptxb;
+	int entry = tpc->cur_tx % NUM_TX_DESC;
+	u32 len = length;
+
+#ifdef DEBUG_RTL8169_TX
+	int stime = currticks();
+	printf ("%s\n", __FUNCTION__);
+	printf("sending %d bytes\n", len);
+#endif
+
+	ioaddr = dev->iobase;
+
+	/* point to the current txb incase multiple tx_rings are used */
+	ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
+	memcpy(ptxb, (char *)packet, (int)length);
+
+	while (len < ETH_ZLEN)
+		ptxb[len++] = '\0';
+
+	tpc->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
+	if (entry != (NUM_TX_DESC - 1)) {
+		tpc->TxDescArray[entry].status =
+		    (OWNbit | FSbit | LSbit) | ((len > ETH_ZLEN) ?
+						len : ETH_ZLEN);
+	} else {
+		tpc->TxDescArray[entry].status =
+		    (OWNbit | EORbit | FSbit | LSbit) |
+		    ((len > ETH_ZLEN) ? length : ETH_ZLEN);
+	}
+	RTL_W8(TxPoll, 0x40);	/* set polling bit */
+
+	tpc->cur_tx++;
+	to = currticks() + TX_TIMEOUT;
+	while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to));	/* wait */
+
+	if (currticks() >= to) {
+#ifdef DEBUG_RTL8169_TX
+		puts ("tx timeout/error\n");
+		printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);
+#endif
+		return 0;
+	} else {
+#ifdef DEBUG_RTL8169_TX
+		puts("tx done\n");
+#endif
+		return length;
+	}
+}
+
+static void rtl8169_set_rx_mode(struct eth_device *dev)
+{
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int rx_mode;
+	u32 tmp = 0;
+
+#ifdef DEBUG_RTL8169
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+	/* IFF_ALLMULTI */
+	/* Too many to filter perfectly -- accept all multicasts. */
+	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+	tmp = rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
+				   rtl_chip_info[tpc->chipset].RxConfigMask);
+
+	RTL_W32(RxConfig, tmp);
+	RTL_W32(MAR0 + 0, mc_filter[0]);
+	RTL_W32(MAR0 + 4, mc_filter[1]);
+}
+
+static void rtl8169_hw_start(struct eth_device *dev)
+{
+	u32 i;
+
+#ifdef DEBUG_RTL8169
+	int stime = currticks();
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+#if 0
+	/* Soft reset the chip. */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+	}
+#endif
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	/* For gigabit rtl8169 */
+	RTL_W16(RxMaxSize, RxPacketMaxSize);
+
+	/* Set Rx Config register */
+	i = rtl8169_rx_config | (RTL_R32(RxConfig) &
+				 rtl_chip_info[tpc->chipset].RxConfigMask);
+	RTL_W32(RxConfig, i);
+
+	/* Set DMA burst size and Interframe Gap Time */
+	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+				(InterFrameGap << TxInterFrameGapShift));
+
+
+	tpc->cur_rx = 0;
+
+	RTL_W32(TxDescStartAddr, virt_to_le32desc(tpc->TxDescArray));
+	RTL_W32(RxDescStartAddr, virt_to_le32desc(tpc->RxDescArray));
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+	udelay(10);
+
+	RTL_W32(RxMissed, 0);
+
+	rtl8169_set_rx_mode(dev);
+
+	/* no early-rx interrupts */
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+#ifdef DEBUG_RTL8169
+	printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);
+#endif
+}
+
+static void rtl8169_init_ring(struct eth_device *dev)
+{
+	int i;
+
+#ifdef DEBUG_RTL8169
+	int stime = currticks();
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+	tpc->cur_rx = 0;
+	tpc->cur_tx = 0;
+	tpc->dirty_tx = 0;
+	memset(tpc->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
+	memset(tpc->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tpc->Tx_skbuff[i] = &txb[i];
+	}
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (i == (NUM_RX_DESC - 1))
+			tpc->RxDescArray[i].status =
+			    (OWNbit | EORbit) + RX_BUF_SIZE;
+		else
+			tpc->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
+
+		tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
+		tpc->RxDescArray[i].buf_addr =
+		    virt_to_bus(tpc->RxBufferRing[i]);
+	}
+
+#ifdef DEBUG_RTL8169
+	printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);
+#endif
+}
+
+/**************************************************************************
+RESET - Finish setting up the ethernet interface
+***************************************************************************/
+static void rtl_reset(struct eth_device *dev, bd_t *bis)
+{
+	int i;
+	u8 diff;
+	u32 TxPhyAddr, RxPhyAddr;
+
+#ifdef DEBUG_RTL8169
+	int stime = currticks();
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+	tpc->TxDescArrays = tx_ring;
+	if (tpc->TxDescArrays == 0)
+		puts("Allot Error");
+	/* Tx Desscriptor needs 256 bytes alignment; */
+	TxPhyAddr = virt_to_bus(tpc->TxDescArrays);
+	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
+	TxPhyAddr += diff;
+	tpc->TxDescArray = (struct TxDesc *) (tpc->TxDescArrays + diff);
+
+	tpc->RxDescArrays = rx_ring;
+	/* Rx Desscriptor needs 256 bytes alignment; */
+	RxPhyAddr = virt_to_bus(tpc->RxDescArrays);
+	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
+	RxPhyAddr += diff;
+	tpc->RxDescArray = (struct RxDesc *) (tpc->RxDescArrays + diff);
+
+	if (tpc->TxDescArrays == NULL || tpc->RxDescArrays == NULL) {
+		puts("Allocate RxDescArray or TxDescArray failed\n");
+		return;
+	}
+
+	rtl8169_init_ring(dev);
+	rtl8169_hw_start(dev);
+	/* Construct a perfect filter frame with the mac address as first match
+	 * and broadcast for all others */
+	for (i = 0; i < 192; i++)
+		txb[i] = 0xFF;
+
+	txb[0] = dev->enetaddr[0];
+	txb[1] = dev->enetaddr[1];
+	txb[2] = dev->enetaddr[2];
+	txb[3] = dev->enetaddr[3];
+	txb[4] = dev->enetaddr[4];
+	txb[5] = dev->enetaddr[5];
+
+#ifdef DEBUG_RTL8169
+	printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);
+#endif
+}
+
+/**************************************************************************
+HALT - Turn off ethernet interface
+***************************************************************************/
+static void rtl_halt(struct eth_device *dev)
+{
+	int i;
+
+#ifdef DEBUG_RTL8169
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+	ioaddr = dev->iobase;
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8(ChipCmd, 0x00);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(IntrMask, 0x0000);
+
+	RTL_W32(RxMissed, 0);
+
+	tpc->TxDescArrays = NULL;
+	tpc->RxDescArrays = NULL;
+	tpc->TxDescArray = NULL;
+	tpc->RxDescArray = NULL;
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		tpc->RxBufferRing[i] = NULL;
+	}
+}
+
+/**************************************************************************
+INIT - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int rtl_init(struct eth_device *dev, bd_t *bis)
+{
+	static int board_idx = -1;
+	static int printed_version = 0;
+	int i, rc;
+	int option = -1, Cap10_100 = 0, Cap1000 = 0;
+
+#ifdef DEBUG_RTL8169
+	printf ("%s\n", __FUNCTION__);
+#endif
+
+	ioaddr = dev->iobase;
+
+	board_idx++;
+
+	printed_version = 1;
+
+	/* point to private storage */
+	tpc = &tpx;
+
+	rc = rtl8169_init_board(dev);
+	if (rc)
+		return rc;
+
+	/* Get MAC address.  FIXME: read EEPROM */
+	for (i = 0; i < MAC_ADDR_LEN; i++)
+		dev->enetaddr[i] = RTL_R8(MAC0 + i);
+
+#ifdef DEBUG_RTL8169
+	printf("MAC Address");
+	for (i = 0; i < MAC_ADDR_LEN; i++)
+		printf(":%02x", dev->enetaddr[i]);
+	putc('\n');
+#endif
+
+#ifdef DEBUG_RTL8169
+	/* Print out some hardware info */
+	printf("%s: at ioaddr 0x%x\n", dev->name, ioaddr);
+#endif
+
+	/* if TBI is not endbled */
+	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
+		int val = mdio_read(PHY_AUTO_NEGO_REG);
+
+		option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+		/* Force RTL8169 in 10/100/1000 Full/Half mode. */
+		if (option > 0) {
+#ifdef DEBUG_RTL8169
+			printf("%s: Force-mode Enabled.\n", dev->name);
+#endif
+			Cap10_100 = 0, Cap1000 = 0;
+			switch (option) {
+			case _10_Half:
+				Cap10_100 = PHY_Cap_10_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _10_Full:
+				Cap10_100 = PHY_Cap_10_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Half:
+				Cap10_100 = PHY_Cap_100_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Full:
+				Cap10_100 = PHY_Cap_100_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _1000_Full:
+				Cap10_100 = PHY_Cap_Null;
+				Cap1000 = PHY_Cap_1000_Full;
+				break;
+			default:
+				break;
+			}
+			mdio_write(PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F));	/* leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
+			mdio_write(PHY_1000_CTRL_REG, Cap1000);
+		} else {
+#ifdef DEBUG_RTL8169
+			printf("%s: Auto-negotiation Enabled.\n",
+			       dev->name);
+#endif
+			/* enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
+			mdio_write(PHY_AUTO_NEGO_REG,
+				   PHY_Cap_10_Half | PHY_Cap_10_Full |
+				   PHY_Cap_100_Half | PHY_Cap_100_Full |
+				   (val & 0x1F));
+
+			/* enable 1000 Full Mode */
+			mdio_write(PHY_1000_CTRL_REG, PHY_Cap_1000_Full);
+
+		}
+
+		/* Enable auto-negotiation and restart auto-nigotiation */
+		mdio_write(PHY_CTRL_REG,
+			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
+		udelay(100);
+
+		/* wait for auto-negotiation process */
+		for (i = 10000; i > 0; i--) {
+			/* check if auto-negotiation complete */
+			if (mdio_read(PHY_STAT_REG) & PHY_Auto_Neco_Comp) {
+				udelay(100);
+				option = RTL_R8(PHYstatus);
+				if (option & _1000bpsF) {
+#ifdef DEBUG_RTL8169
+					printf("%s: 1000Mbps Full-duplex operation.\n",
+					     dev->name);
+#endif
+				} else {
+#ifdef DEBUG_RTL8169
+					printf
+					    ("%s: %sMbps %s-duplex operation.\n",
+					     dev->name,
+					     (option & _100bps) ? "100" :
+					     "10",
+					     (option & FullDup) ? "Full" :
+					     "Half");
+#endif
+				}
+				break;
+			} else {
+				udelay(100);
+			}
+		}		/* end for-loop to wait for auto-negotiation process */
+
+	} else {
+		udelay(100);
+#ifdef DEBUG_RTL8169
+		printf
+		    ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
+		     dev->name,
+		     (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+#endif
+	}
+
+	return 1;
+}
+
+int rtl8169_initialize(bd_t *bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	u32 iobase;
+	int idx=0;
+
+	while(1){
+		/* Find RTL8169 */
+		if ((devno = pci_find_devices(supported, idx++)) < 0)
+			break;
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+		iobase &= ~0xf;
+
+		debug ("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
+
+		dev = (struct eth_device *)malloc(sizeof *dev);
+
+		sprintf (dev->name, "RTL8169#%d", card_number);
+
+		dev->priv = (void *) devno;
+		dev->iobase = (int)bus_to_phys(iobase);
+
+		dev->init = rtl_reset;
+		dev->halt = rtl_halt;
+		dev->send = rtl_send;
+		dev->recv = rtl_recv;
+
+		eth_register (dev);
+
+		rtl_init(dev, bis);
+
+		card_number++;
+	}
+	return card_number;
+}
+
+#endif
diff --git a/drivers/net/s3c4510b_eth.c b/drivers/net/s3c4510b_eth.c
new file mode 100644
index 0000000..3d9066a
--- /dev/null
+++ b/drivers/net/s3c4510b_eth.c
@@ -0,0 +1,246 @@
+/***********************************************************************
+ *
+ * Copyright (c) 2004	Cucy Systems (http://www.cucy.com)
+ * Curt Brune <curt@cucy.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Description:   Ethernet interface for Samsung S3C4510B SoC
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_DRIVER_S3C4510_ETH
+
+#include <command.h>
+#include <net.h>
+#include <asm/hardware.h>
+#include "s3c4510b_eth.h"
+
+static TX_FrameDescriptor    txFDbase[ETH_MaxTxFrames];
+static MACFrame           txFrameBase[ETH_MaxTxFrames];
+static RX_FrameDescriptor    rxFDbase[PKTBUFSRX];
+static ETH                      m_eth;
+
+static s32 TxFDinit( ETH *eth) {
+
+	s32 i;
+	MACFrame *txFrmBase;
+
+	/* disable cache for access to the TX buffers */
+	txFrmBase = (MACFrame *)( (u32)txFrameBase | CACHE_DISABLE_MASK);
+
+	/* store start of Tx descriptors and set current */
+	eth->m_curTX_FD  =  (TX_FrameDescriptor *) ((u32)txFDbase | CACHE_DISABLE_MASK);
+	eth->m_baseTX_FD = eth->m_curTX_FD;
+
+	for ( i = 0; i < ETH_MaxTxFrames; i++) {
+		eth->m_baseTX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)&txFrmBase[i];
+		eth->m_baseTX_FD[i].m_frameDataPtr.bf.owner   = 0x0; /* CPU owner */
+		eth->m_baseTX_FD[i].m_opt.ui                  = 0x0;
+		eth->m_baseTX_FD[i].m_status.ui               = 0x0;
+		eth->m_baseTX_FD[i].m_nextFD                  = &eth->m_baseTX_FD[i+1];
+	}
+
+	/* make the list circular */
+	eth->m_baseTX_FD[i-1].m_nextFD          = &eth->m_baseTX_FD[0];
+
+	PUT_REG( REG_BDMATXPTR, (u32)eth->m_curTX_FD);
+
+	return 0;
+}
+
+static s32 RxFDinit( ETH *eth) {
+
+	s32 i;
+	/*  MACFrame *rxFrmBase; */
+
+	/* disable cache for access to the RX buffers */
+	/*  rxFrmBase = (MACFrame *)( (u32)rxFrameBase | CACHE_DISABLE_MASK); */
+
+	/* store start of Rx descriptors and set current */
+	eth->m_curRX_FD = (RX_FrameDescriptor *)((u32)rxFDbase | CACHE_DISABLE_MASK);
+	eth->m_baseRX_FD = eth->m_curRX_FD;
+	for ( i = 0; i < PKTBUFSRX; i++) {
+		eth->m_baseRX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)NetRxPackets[i] | CACHE_DISABLE_MASK;
+		eth->m_baseRX_FD[i].m_frameDataPtr.bf.owner   = 0x1; /* BDMA owner */
+		eth->m_baseRX_FD[i].m_reserved                = 0x0;
+		eth->m_baseRX_FD[i].m_status.ui               = 0x0;
+		eth->m_baseRX_FD[i].m_nextFD                  = &eth->m_baseRX_FD[i+1];
+	}
+
+	/* make the list circular */
+	eth->m_baseRX_FD[i-1].m_nextFD                  = &eth->m_baseRX_FD[0];
+
+	PUT_REG( REG_BDMARXPTR, (u32)eth->m_curRX_FD);
+
+	return 0;
+}
+
+/*
+ * Public u-boot interface functions below
+ */
+
+int eth_init(bd_t *bis)
+{
+
+	ETH *eth = &m_eth;
+
+	/* store our MAC address */
+	eth->m_mac = bis->bi_enetaddr;
+
+	/* setup DBMA and MAC */
+	PUT_REG( REG_BDMARXCON, ETH_BRxRS);   /* reset BDMA RX machine */
+	PUT_REG( REG_BDMATXCON, ETH_BTxRS);   /* reset BDMA TX machine */
+	PUT_REG( REG_MACCON   , ETH_SwReset); /* reset MAC machine */
+	PUT_REG( REG_BDMARXLSZ, sizeof(MACFrame));
+	PUT_REG( REG_MACCON   , 0);           /* reset MAC machine */
+
+	/* init frame descriptors */
+	TxFDinit( eth);
+	RxFDinit( eth);
+
+	/* init the CAM with our MAC address */
+	PUT_REG( REG_CAM_BASE,       (eth->m_mac[0] << 24) |
+		(eth->m_mac[1] << 16) |
+		(eth->m_mac[2] <<  8) |
+		(eth->m_mac[3]));
+	PUT_REG( REG_CAM_BASE + 0x4, (eth->m_mac[4] << 24) |
+		(eth->m_mac[5] << 16));
+
+	/* enable CAM address 1 -- the MAC we just loaded */
+	PUT_REG( REG_CAMEN, 0x1);
+
+	PUT_REG( REG_CAMCON,
+		ETH_BroadAcc |	/* accept broadcast packetes */
+		ETH_CompEn); /* enable compare mode (check against the CAM) */
+
+	/* configure the BDMA Transmitter control */
+	PUT_REG( REG_BDMATXCON,
+		ETH_BTxBRST   |	/* BDMA Tx burst size 16 words  */
+		ETH_BTxMSL110 |	/* BDMA Tx wait to fill 6/8 of the BDMA */
+		ETH_BTxSTSKO  |	/* BDMA Tx interrupt(Stop) on non-owner TX FD */
+		ETH_BTxEn);	/* BDMA Tx Enable  */
+
+	/* configure the MAC Transmitter control */
+	PUT_REG( REG_MACTXCON,
+		ETH_EnComp | /* interrupt when the MAC transmits or discards packet */
+		ETH_TxEn);	/* MAC transmit enable */
+
+	/* configure the BDMA Receiver control */
+	PUT_REG( REG_BDMARXCON,
+		ETH_BRxBRST   |	/* BDMA Rx Burst Size 16 words */
+		ETH_BRxSTSKO  |	/* BDMA Rx interrupt(Stop) on non-owner RX FD */
+		ETH_BRxMAINC  |	/* BDMA Rx Memory Address increment */
+		ETH_BRxDIE    |	/* BDMA Rx Every Received Frame Interrupt Enable */
+		ETH_BRxNLIE   |	/* BDMA Rx NULL List Interrupt Enable */
+		ETH_BRxNOIE   |	/* BDMA Rx Not Owner Interrupt Enable */
+		ETH_BRxLittle |	/* BDMA Rx Little endian */
+		ETH_BRxEn);	/* BDMA Rx Enable */
+
+	/* configure the MAC Receiver control */
+	PUT_REG( REG_MACRXCON,
+		ETH_RxEn);	/* MAC ETH_RxEn */
+
+	return 0;
+
+}
+
+/* Send a packet	*/
+s32 eth_send(volatile void *packet, s32 length)
+{
+
+	u32 i;
+	ETH *eth = &m_eth;
+
+	if ( eth->m_curTX_FD->m_frameDataPtr.bf.owner) {
+		printf("eth_send(): TX Frame.  CPU not owner.\n");
+		return -1;
+	}
+
+	/* copy user data into frame data pointer */
+	memcpy((void *)((u32)(eth->m_curTX_FD->m_frameDataPtr.bf.dataPtr)),
+	       (void *)packet,
+	       length);
+
+	/* Set TX Frame flags */
+	eth->m_curTX_FD->m_opt.bf.widgetAlign  = 0;
+	eth->m_curTX_FD->m_opt.bf.frameDataDir = 1;
+	eth->m_curTX_FD->m_opt.bf.littleEndian = 1;
+	eth->m_curTX_FD->m_opt.bf.macTxIrqEnbl = 1;
+	eth->m_curTX_FD->m_opt.bf.no_crc       = 0;
+	eth->m_curTX_FD->m_opt.bf.no_padding   = 0;
+
+	/* Set TX Frame length */
+	eth->m_curTX_FD->m_status.bf.len       = length;
+
+	/* Change ownership to BDMA */
+	eth->m_curTX_FD->m_frameDataPtr.bf.owner = 1;
+
+	/* Enable MAC and BDMA Tx control register */
+	SET_REG( REG_BDMATXCON, ETH_BTxEn);
+	SET_REG( REG_MACTXCON,  ETH_TxEn);
+
+	/* poll on TX completion status */
+	while ( !eth->m_curTX_FD->m_status.bf.complete) {
+		/* sleep  */
+		for ( i = 0; i < 0x10000; i ++);
+	}
+
+	/* Change the Tx frame descriptor for next use */
+	eth->m_curTX_FD = eth->m_curTX_FD->m_nextFD;
+
+	return 0;
+}
+
+/* Check for received packets	*/
+s32 eth_rx (void)
+{
+	s32 nLen = 0;
+	ETH *eth = &m_eth;
+
+	/* check if packet ready */
+	if ( (GET_REG( REG_BDMASTAT)) & ETH_S_BRxRDF) {
+		/* process all waiting packets */
+		while ( !eth->m_curRX_FD->m_frameDataPtr.bf.owner) {
+			nLen = eth->m_curRX_FD->m_status.bf.len;
+			/* call back u-boot -- may call eth_send() */
+			NetReceive ((u8 *)eth->m_curRX_FD->m_frameDataPtr.ui, nLen);
+			/* set owner back to CPU */
+			eth->m_curRX_FD->m_frameDataPtr.bf.owner = 1;
+			/* clear status */
+			eth->m_curRX_FD->m_status.ui = 0x0;
+			/* advance to next descriptor */
+			eth->m_curRX_FD = eth->m_curRX_FD->m_nextFD;
+			/* clear received frame bit */
+			PUT_REG( REG_BDMASTAT, ETH_S_BRxRDF);
+		}
+	}
+
+	return nLen;
+}
+
+/* Halt ethernet engine */
+void eth_halt(void)
+{
+	/* disable MAC */
+	PUT_REG( REG_MACCON, ETH_HaltReg);
+}
+
+#endif
diff --git a/drivers/net/s3c4510b_eth.h b/drivers/net/s3c4510b_eth.h
new file mode 100644
index 0000000..cbddba7
--- /dev/null
+++ b/drivers/net/s3c4510b_eth.h
@@ -0,0 +1,302 @@
+#ifndef __S3C4510B_ETH_H
+#define __S3C4510B_ETH_H
+/*
+ * Copyright (c) 2004	Cucy Systems (http://www.cucy.com)
+ * Curt Brune <curt@cucy.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * MODULE:        $Id:$
+ * Description:   Ethernet interface
+ * Runtime Env:   ARM7TDMI
+ * Change History:
+ *     03-02-04    Create (Curt Brune) curt@cucy.com
+ *
+ */
+
+#define __packed    __attribute__ ((packed))
+
+#define ETH_MAC_ADDR_SIZE           (6)    /*  dst,src addr is 6bytes each */
+#define ETH_MaxTxFrames             (16)   /*  Max number of Tx Frames */
+
+/*  Buffered DMA Receiver Control Register  */
+#define ETH_BRxBRST     0x0000F  /*  BDMA Rx Burst Size * BRxBRST  */
+				 /*  = Burst Data Size 16 */
+#define ETH_BRxSTSKO    0x00020  /*  BDMA Rx Stop/Skip  Frame or Interrupt(=1)  */
+				 /*  case of not OWNER the current Frame  */
+#define ETH_BRxMAINC    0x00040  /*  BDMA Rx Memory Address Inc/Dec  */
+#define ETH_BRxDIE      0x00080  /*  BDMA Rx Every Received Frame Interrupt Enable */
+#define ETH_BRxNLIE     0x00100  /*  BDMA Rx NULL List Interrupt Enable  */
+#define ETH_BRxNOIE     0x00200  /*  BDMA Rx Not Owner Interrupt Enable */
+#define ETH_BRxMSOIE    0x00400  /*  BDMA Rx Maximum Size over Interrupr Enable  */
+#define ETH_BRxLittle   0x00800  /*  BDMA Rx Big/Little Endian  */
+#define ETH_BRxBig      0x00000  /*  BDMA Rx Big/Little Endian */
+#define ETH_BRxWA01     0x01000  /*  BDMA Rx Word Alignment- one invalid byte  */
+#define ETH_BRxWA10     0x02000  /*  BDMA Rx Word Alignment- two invalid byte */
+#define ETH_BRxWA11     0x03000  /*  BDMA Rx Word Alignment- three invalid byte  */
+#define ETH_BRxEn       0x04000  /*  BDMA Rx Enable */
+#define ETH_BRxRS       0x08000  /*  BDMA Rx Reset */
+#define ETH_RxEmpty     0x10000  /*  BDMA Rx Buffer empty interrupt  */
+#define ETH_BRxEarly    0x20000  /*  BDMA Rx Early notify Interrupt */
+
+/*  Buffered DMA Trasmit Control Register(BDMATXCON)  */
+#define ETH_BTxBRST     0x0000F  /*  BDMA Tx Burst Size = 16  */
+#define ETH_BTxSTSKO    0x00020  /*  BDMA Tx Stop/Skip Frame or Interrupt in case */
+				 /*  of not Owner the current frame  */
+#define ETH_BTxCPIE     0x00080  /*  BDMA Tx Complete to send control  */
+				 /*  packet Enable */
+#define ETH_BTxNOIE     0x00200  /*  BDMA Tx Buffer Not Owner */
+#define ETH_BTxEmpty    0x00400  /*  BDMA Tx Buffer Empty Interrupt  */
+
+/*  BDMA Tx buffer can be moved to the MAC Tx IO when the new frame comes in.  */
+#define ETH_BTxMSL000   0x00000  /*  No wait to fill the BDMA  */
+#define ETH_BTxMSL001   0x00800  /*  wait to fill 1/8 of the BDMA  */
+#define ETH_BTxMSL010   0x01000  /*  wait to fill 2/8 of the BDMA */
+#define ETH_BTxMSL011   0x01800  /*  wait to fill 3/8 of the BDMA */
+#define ETH_BTxMSL100   0x02000  /*  wait to fill 4/8 of the BDMA */
+#define ETH_BTxMSL101   0x02800  /*  wait to fill 5/8 of the BDMA */
+#define ETH_BTxMSL110   0x03000  /*  wait to fill 6/8 of the BDMA */
+#define ETH_BTxMSL111   0x03800  /*  wait to fill 7/8 of the BDMA */
+#define ETH_BTxEn       0x04000  /*  BDMA Tx Enable  */
+#define ETH_BTxRS       0x08000  /*  BDMA Tx Reset  */
+
+/*  BDMA Status Register  */
+#define ETH_S_BRxRDF    0x00001  /*  BDMA Rx Done Every Received Frame  */
+#define ETH_S_BRxNL     0x00002  /*  BDMA Rx NULL List  */
+#define ETH_S_BRxNO     0x00004  /*  BDMA Rx Not Owner  */
+#define ETH_S_BRxMSO    0x00008  /*  BDMA Rx Maximum Size Over  */
+#define ETH_S_BRxEmpty  0x00010  /*  BDMA Rx Buffer Empty  */
+#define ETH_S_BRxSEarly 0x00020  /*  Early Notify  */
+#define ETH_S_BRxFRF    0x00080  /*  One more frame data in BDMA receive buffer  */
+#define ETH_S_BTxCCP    0x10000  /*  BDMA Tx Complete to send Control Packet  */
+#define ETH_S_BTxNL     0x20000  /*  BDMA Tx Null List  */
+#define ETH_S_BTxNO     0x40000  /*  BDMA Tx Not Owner */
+#define ETH_S_BTxEmpty  0x100000 /*  BDMA Tx Buffer Empty  */
+
+/*  MAC Control Register  */
+#define ETH_HaltReg     0x0001   /*  stop transmission and reception  */
+				 /*  after completion of any current packets  */
+#define ETH_HaltImm     0x0002   /*  Stop transmission and reception immediately  */
+#define ETH_SwReset     0x0004   /*  reset all Ethernet controller state machines */
+				 /*  and FIFOs  */
+#define ETH_FullDup     0x0008   /*  allow transmission to begin while reception */
+				 /*  is occurring  */
+#define ETH_MACLoop     0x0010   /*  MAC loopback */
+#define ETH_ConnM00     0x0000   /*  Automatic-default  */
+#define ETH_ConnM01     0x0020   /*  Force 10Mbits endec */
+#define ETH_ConnM10     0x0040   /*  Force MII (rate determined by MII clock  */
+#define ETH_MIIOFF      0x0040   /*  Force MII (rate determined by MII clock  */
+#define ETH_Loop10      0x0080   /*  Loop 10Mbps  */
+#define ETH_MissRoll    0x0400   /*  Missed error counter rolled over  */
+#define ETH_MDCOFF      0x1000   /*  MII Station Management Clock Off */
+#define ETH_EnMissRoll  0x2000   /*  Interrupt when missed error counter rolls  */
+				 /*  over  */
+#define ETH_Link10      0x8000   /*  Link status 10Mbps  */
+
+/*  CAM control register(CAMCON)  */
+#define ETH_StationAcc  0x0001   /*  Accept any packet with a unicast station  */
+				 /*  address  */
+#define ETH_GroupAcc    0x0002   /*  Accept any packet with multicast-group  */
+				 /*  station address   */
+#define ETH_BroadAcc    0x0004   /*  Accept any packet with a broadcast station */
+				 /*  address  */
+#define ETH_NegCAM      0x0008   /*  0: Accept packets CAM recognizes,  */
+				 /*     reject others */
+				 /*  1: reject packets CAM recognizes,  */
+				 /*     accept others  */
+#define ETH_CompEn      0x0010   /*  Compare Enable mode */
+
+/*  Transmit Control Register(MACTXCON) */
+#define ETH_TxEn        0x0001   /*  transmit Enable  */
+#define ETH_TxHalt      0x0002   /*  Transmit Halt Request  */
+#define ETH_NoPad       0x0004   /*  suppress Padding  */
+#define ETH_NoCRC       0x0008   /*  Suppress CRC  */
+#define ETH_FBack       0x0010   /*  Fast Back-off */
+#define ETH_NoDef       0x0020   /*  Disable the defer counter */
+#define ETH_SdPause     0x0040   /*  Send Pause */
+#define ETH_MII10En     0x0080   /*  MII 10Mbps mode enable */
+#define ETH_EnUnder     0x0100   /*  Enable Underrun */
+#define ETH_EnDefer     0x0200   /*  Enable Deferral */
+#define ETH_EnNCarr     0x0400   /*  Enable No Carrier  */
+#define ETH_EnExColl    0x0800   /*  interrupt if 16 collision occur  */
+				 /*  in the same packet  */
+#define ETH_EnLateColl  0x1000   /*  interrupt if collision occurs after  */
+				 /*  512 bit times(64 bytes times)  */
+#define ETH_EnTxPar     0x2000   /*  interrupt if the MAC transmit FIFO  */
+				 /*  has a parity error  */
+#define ETH_EnComp      0x4000   /*  interrupt when the MAC transmits or  */
+				 /*  discards one packet  */
+
+/*  Transmit Status Register(MACTXSTAT) */
+#define ETH_ExColl      0x0010   /*  Excessive collision  */
+#define ETH_TxDeffered  0x0020   /*  set if 16 collisions occur for same packet */
+#define ETH_Paused      0x0040   /*  packet waited because of pause during  */
+				 /*  transmission  */
+#define ETH_IntTx       0x0080   /*  set if transmission of packet causes an  */
+				 /*  interrupt condiftion  */
+#define ETH_Under       0x0100   /*  MAC transmit FIFO becomes empty during  */
+				 /*  transmission  */
+#define ETH_Defer       0x0200   /*  MAC defers for MAC deferral  */
+#define ETH_NCarr       0x0400   /*  No carrier sense detected during the  */
+				 /*  transmission of a packet  */
+#define ETH_SQE         0x0800   /*  Signal Quality Error */
+#define ETH_LateColl    0x1000   /*  a collision occures after 512 bit times  */
+#define ETH_TxPar       0x2000   /*  MAC transmit FIFO has detected a parity error */
+#define ETH_Comp        0x4000   /*  MAC transmit or discards one packet  */
+#define ETH_TxHalted    0x8000   /*  Transmission was halted by clearing  */
+				 /*  TxEn or Halt immedite  */
+
+/*  Receive Control Register (MACRXCON)  */
+#define ETH_RxEn        0x0001
+#define ETH_RxHalt      0x0002
+#define ETH_LongEn      0x0004
+#define ETH_ShortEn     0x0008
+#define ETH_StripCRC    0x0010
+#define ETH_PassCtl     0x0020
+#define ETH_IgnoreCRC   0x0040
+#define ETH_EnAlign     0x0100
+#define ETH_EnCRCErr    0x0200
+#define ETH_EnOver      0x0400
+#define ETH_EnLongErr   0x0800
+#define ETH_EnRxPar     0x2000
+#define ETH_EnGood      0x4000
+
+/*  Receive Status Register(MACRXSTAT) */
+#define ETH_MCtlRecd    0x0020
+#define ETH_MIntRx      0x0040
+#define ETH_MRx10Stat   0x0080
+#define ETH_MAllignErr  0x0100
+#define ETH_MCRCErr     0x0200
+#define ETH_MOverflow   0x0400
+#define ETH_MLongErr    0x0800
+#define ETH_MRxPar      0x2000
+#define ETH_MRxGood     0x4000
+#define ETH_MRxHalted   0x8000
+
+/*  type of ethernet packets */
+#define ETH_TYPE_ARP  (0x0806)
+#define ETH_TYPE_IP   (0x0800)
+
+#define ETH_HDR_SIZE  (14)
+
+/*  bit field for frame data pointer word */
+typedef struct __BF_FrameDataPtr {
+	u32 dataPtr:31;
+	u32   owner: 1;
+} BF_FrameDataPtr;
+
+typedef union _FrameDataPtr {
+	u32             ui;
+	BF_FrameDataPtr bf;
+} FrameDataPtr;
+
+typedef struct __BF_TX_Options {
+	u32    no_padding: 1;
+	u32        no_crc: 1;
+	u32  macTxIrqEnbl: 1;
+	u32  littleEndian: 1;
+	u32  frameDataDir: 1;
+	u32   widgetAlign: 2;
+	u32      reserved:25;
+} BF_TX_Options;
+
+typedef union _TX_Options {
+	u32    ui;
+	BF_TX_Options   bf;
+} TX_Options;
+
+typedef struct __BF_RX_Status {
+	u32           len:16;	/*  frame length */
+	u32     reserved1: 3;
+	u32       overMax: 1;
+	u32     reserved2: 1;
+	u32       ctrlRcv: 1;
+	u32         intRx: 1;
+	u32      rx10stat: 1;
+	u32      alignErr: 1;
+	u32        crcErr: 1;
+	u32      overFlow: 1;
+	u32       longErr: 1;
+	u32     reserved3: 1;
+	u32     parityErr: 1;
+	u32          good: 1;
+	u32        halted: 1;
+} BF_RX_Status;
+
+typedef union _RX_Status {
+	u32             ui;
+	BF_RX_Status    bf;
+} RX_Status;
+
+typedef struct __BF_TX_Status {
+	u32           len:16;	/*  frame length */
+	u32     txCollCnt: 4;
+	u32        exColl: 1;
+	u32       txDefer: 1;
+	u32        paused: 1;
+	u32         intTx: 1;
+	u32      underRun: 1;
+	u32         defer: 1;
+	u32     noCarrier: 1;
+	u32         SQErr: 1;
+	u32      lateColl: 1;
+	u32     parityErr: 1;
+	u32      complete: 1;
+	u32        halted: 1;
+} BF_TX_Status;
+
+typedef union _TX_Status {
+	u32    ui;
+	BF_TX_Status    bf;
+} TX_Status;
+
+/*  TX descriptor structure  */
+typedef struct __TX_FrameDescriptor {
+	volatile FrameDataPtr  m_frameDataPtr;
+	TX_Options                      m_opt;
+	volatile TX_Status           m_status;
+	struct __TX_FrameDescriptor *m_nextFD;
+} TX_FrameDescriptor;
+
+/*  RX descriptor structure  */
+typedef struct __RX_FrameDescriptor {
+	volatile FrameDataPtr  m_frameDataPtr;
+	u32                        m_reserved;
+	volatile RX_Status           m_status;
+	struct __RX_FrameDescriptor *m_nextFD;
+} RX_FrameDescriptor;
+
+/*  MAC Frame Structure */
+typedef struct __MACFrame {
+	u8     m_dstAddr[6] __packed;
+	u8     m_srcAddr[6] __packed;
+	u16  m_lengthOrType __packed;
+	u8  m_payload[1506] __packed;
+} MACFrame;
+
+/* Ethernet Control block */
+typedef struct __ETH {
+	TX_FrameDescriptor   *m_curTX_FD; /*  pointer to current TX frame descriptor */
+	TX_FrameDescriptor  *m_baseTX_FD; /*  pointer to base TX frame descriptor    */
+	RX_FrameDescriptor   *m_curRX_FD; /*  pointer to current RX frame descriptor */
+	RX_FrameDescriptor  *m_baseRX_FD; /*  pointer to base RX frame descriptor    */
+	u8                        *m_mac; /*  pointer to our MAC address             */
+} ETH;
+
+#endif
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
new file mode 100644
index 0000000..a7d4a3b
--- /dev/null
+++ b/drivers/net/sk98lin/Makefile
@@ -0,0 +1,120 @@
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+# File: drivers/sk98lin/Makefile
+#
+# Makefile for the SysKonnect SK-98xx device driver.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libsk98lin.a
+
+COBJS-y += skge.o
+COBJS-y += skaddr.o
+COBJS-y += skgehwt.o
+COBJS-y += skgeinit.o
+COBJS-y += skgepnmi.o
+COBJS-y += skgesirq.o
+COBJS-y += ski2c.o
+COBJS-y += sklm80.o
+COBJS-y += skqueue.o
+COBJS-y += skrlmt.o
+COBJS-y += sktimer.o
+COBJS-y += skvpd.o
+COBJS-y += skxmac2.o
+COBJS-y += skcsum.o
+#COBJS-y += skproc.o
+
+COBJS-y += uboot_skb.o
+COBJS-y += uboot_drv.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+# DBGDEF =  \
+# -DDEBUG
+
+ifdef DEBUG
+DBGDEF +=  \
+-DSK_DEBUG_CHKMOD=0x00000000L \
+-DSK_DEBUG_CHKCAT=0x00000000L
+endif
+
+
+# **** possible debug modules for SK_DEBUG_CHKMOD *****************
+# SK_DBGMOD_MERR        0x00000001L     /* general module error indication */
+# SK_DBGMOD_HWM         0x00000002L     /* Hardware init module */
+# SK_DBGMOD_RLMT        0x00000004L     /* RLMT module */
+# SK_DBGMOD_VPD         0x00000008L     /* VPD module */
+# SK_DBGMOD_I2C         0x00000010L     /* I2C module */
+# SK_DBGMOD_PNMI        0x00000020L     /* PNMI module */
+# SK_DBGMOD_CSUM        0x00000040L     /* CSUM module */
+# SK_DBGMOD_ADDR        0x00000080L     /* ADDR module */
+# SK_DBGMOD_DRV         0x00010000L     /* DRV module */
+
+# **** possible debug categories for SK_DEBUG_CHKCAT **************
+# *** common modules ***
+# SK_DBGCAT_INIT        0x00000001L     module/driver initialization
+# SK_DBGCAT_CTRL        0x00000002L     controlling: add/rmv MCA/MAC and other controls (IOCTL)
+# SK_DBGCAT_ERR         0x00000004L     error handling paths
+# SK_DBGCAT_TX          0x00000008L     transmit path
+# SK_DBGCAT_RX          0x00000010L     receive path
+# SK_DBGCAT_IRQ         0x00000020L     general IRQ handling
+# SK_DBGCAT_QUEUE       0x00000040L     any queue management
+# SK_DBGCAT_DUMP        0x00000080L     large data output e.g. hex dump
+# SK_DBGCAT_FATAL       0x00000100L     large data output e.g. hex dump
+
+# *** driver (file skge.c) ***
+# SK_DBGCAT_DRV_ENTRY           0x00010000      entry points
+# SK_DBGCAT_DRV_???             0x00020000      not used
+# SK_DBGCAT_DRV_MCA             0x00040000      multicast
+# SK_DBGCAT_DRV_TX_PROGRESS     0x00080000      tx path
+# SK_DBGCAT_DRV_RX_PROGRESS     0x00100000      rx path
+# SK_DBGCAT_DRV_PROGRESS        0x00200000      general runtime
+# SK_DBGCAT_DRV_???             0x00400000      not used
+# SK_DBGCAT_DRV_PROM            0x00800000      promiscuous mode
+# SK_DBGCAT_DRV_TX_FRAME        0x01000000      display tx frames
+# SK_DBGCAT_DRV_ERROR           0x02000000      error conditions
+# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
+# SK_DBGCAT_DRV_EVENT           0x08000000      driver events
+
+EXTRA_CFLAGS += -I. -DSK_USE_CSUM $(DBGDEF)
+
+CFLAGS += $(EXTRA_CFLAGS)
+HOST_CFLAGS += $(EXTRA_CFLAGS)
+
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h
new file mode 100644
index 0000000..981a4ca
--- /dev/null
+++ b/drivers/net/sk98lin/h/lm80.h
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * Name:	lm80.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 2002/04/25 11:04:10 $
+ * Purpose:	Contains all defines for the LM80 Chip
+ *		(National Semiconductor).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: lm80.h,v $
+ *	Revision 1.4  2002/04/25 11:04:10  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.3  1999/11/22 13:41:19  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.2  1999/03/12 13:26:51  malthoff
+ *	remove __STDC__.
+ *
+ *	Revision 1.1  1998/06/19 09:28:31  malthoff
+ *	created.
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_LM80_H
+#define __INC_LM80_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * LM80 register definition
+ *
+ * All registers are 8 bit wide
+ */
+#define	LM80_CFG			0x00	/* Configuration Register */
+#define	LM80_ISRC_1			0x01	/* Interrupt Status Register 1 */
+#define LM80_ISRC_2			0x02	/* Interrupt Status Register 2 */
+#define LM80_IMSK_1			0x03	/* Interrupt Mask Register 1 */
+#define LM80_IMSK_2			0x04	/* Interrupt Mask Register 2 */
+#define LM80_FAN_CTRL		0x05	/* Fan Devisor/RST#/OS# Register */
+#define LM80_TEMP_CTRL		0x06	/* OS# Config, Temp Res. Reg */
+	/* 0x07 - 0x1f reserved	*/
+	/* current values */
+#define LM80_VT0_IN			0x20	/* current Voltage 0 value */
+#define LM80_VT1_IN			0x21	/* current Voltage 1 value */
+#define LM80_VT2_IN			0x22	/* current Voltage 2 value */
+#define LM80_VT3_IN			0x23	/* current Voltage 3 value */
+#define LM80_VT4_IN			0x24	/* current Voltage 4 value */
+#define LM80_VT5_IN			0x25	/* current Voltage 5 value */
+#define LM80_VT6_IN			0x26	/* current Voltage 6 value */
+#define LM80_TEMP_IN		0x27	/* current Temperature value */
+#define LM80_FAN1_IN		0x28	/* current Fan 1 count */
+#define LM80_FAN2_IN		0x29	/* current Fan 2 count */
+	/* limit values */
+#define LM80_VT0_HIGH_LIM	0x2a	/* high limit val for Voltage 0 */
+#define LM80_VT0_LOW_LIM	0x2b	/* low limit val for Voltage 0 */
+#define LM80_VT1_HIGH_LIM	0x2c	/* high limit val for Voltage 1 */
+#define LM80_VT1_LOW_LIM	0x2d	/* low limit val for Voltage 1 */
+#define LM80_VT2_HIGH_LIM	0x2e	/* high limit val for Voltage 2 */
+#define LM80_VT2_LOW_LIM	0x2f	/* low limit val for Voltage 2 */
+#define LM80_VT3_HIGH_LIM	0x30	/* high limit val for Voltage 3 */
+#define LM80_VT3_LOW_LIM	0x31	/* low limit val for Voltage 3 */
+#define LM80_VT4_HIGH_LIM	0x32	/* high limit val for Voltage 4 */
+#define LM80_VT4_LOW_LIM	0x33	/* low limit val for Voltage 4 */
+#define LM80_VT5_HIGH_LIM	0x34	/* high limit val for Voltage 5 */
+#define LM80_VT5_LOW_LIM	0x35	/* low limit val for Voltage 5 */
+#define LM80_VT6_HIGH_LIM	0x36	/* high limit val for Voltage 6 */
+#define LM80_VT6_LOW_LIM	0x37	/* low limit val for Voltage 6 */
+#define LM80_THOT_LIM_UP	0x38	/* hot temperature limit (high) */
+#define LM80_THOT_LIM_LO	0x39	/* hot temperature limit (low) */
+#define LM80_TOS_LIM_UP		0x3a	/* OS temperature limit (high) */
+#define LM80_TOS_LIM_LO		0x3b	/* OS temperature limit (low) */
+#define	LM80_FAN1_COUNT_LIM	0x3c	/* Fan 1 count limit (high) */
+#define	LM80_FAN2_COUNT_LIM	0x3d	/* Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+/*
+ * LM80 bit definitions
+ */
+
+/*	LM80_CFG		Configuration Register */
+#define LM80_CFG_START		(1<<0)	/* start monitoring operation */
+#define LM80_CFG_INT_ENA	(1<<1)	/* enables the INT# Interrupt output */
+#define LM80_CFG_INT_POL	(1<<2)	/* INT# pol: 0 act low, 1 act high */
+#define LM80_CFG_INT_CLR	(1<<3)	/* disables INT#/RST_OUT#/OS# outputs */
+#define LM80_CFG_RESET		(1<<4)	/* signals a reset */
+#define LM80_CFG_CHASS_CLR	(1<<5)	/* clears Chassis Intrusion (CI) pin */
+#define LM80_CFG_GPO		(1<<6)	/* drives the GPO# pin */
+#define LM80_CFG_INIT		(1<<7)	/* restore power on defaults */
+
+/*	LM80_ISRC_1		Interrupt Status Register 1 */
+/*	LM80_IMSK_1		Interrupt Mask Register 1 */
+#define LM80_IS_VT0			(1<<0)	/* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1			(1<<1)	/* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2			(1<<2)	/* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3			(1<<3)	/* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4			(1<<4)	/* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5			(1<<5)	/* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6			(1<<6)	/* limit exceeded for Voltage 6 */
+#define LM80_IS_INT_IN		(1<<7)	/* state of INT_IN# */
+
+/*	LM80_ISRC_2		Interrupt Status Register 2 */
+/*	LM80_IMSK_2		Interrupt Mask Register 2 */
+#define	LM80_IS_TEMP		(1<<0)	/* HOT temperature limit exceeded */
+#define LM80_IS_BTI			(1<<1)	/* state of BTI# pin */
+#define LM80_IS_FAN1		(1<<2)	/* count limit exceeded for Fan 1 */
+#define LM80_IS_FAN2		(1<<3)	/* count limit exceeded for Fan 2 */
+#define LM80_IS_CI			(1<<4)	/* Chassis Intrusion occured */
+#define LM80_IS_OS			(1<<5)	/* OS temperature limit exceeded */
+	/* bit 6 and 7 are reserved in LM80_ISRC_2 */
+#define LM80_IS_HT_IRQ_MD	(1<<6)	/* Hot temperature interrupt mode */
+#define LM80_IS_OT_IRQ_MD	(1<<7)	/* OS temperature interrupt mode */
+
+/*	LM80_FAN_CTRL		Fan Devisor/RST#/OS# Register */
+#define LM80_FAN1_MD_SEL	(1<<0)	/* Fan 1 mode select */
+#define LM80_FAN2_MD_SEL	(1<<1)	/* Fan 2 mode select */
+#define LM80_FAN1_PRM_CTL	(3<<2)	/* Fan 1 speed control */
+#define LM80_FAN2_PRM_CTL	(3<<4)	/* Fan 2 speed control */
+#define LM80_FAN_OS_ENA		(1<<6)	/* enable OS mode on RST_OUT#/OS# pins*/
+#define LM80_FAN_RST_ENA	(1<<7)	/* sets RST_OUT#/OS# pins in RST mode */
+
+/*	LM80_TEMP_CTRL		OS# Config, Temp Res. Reg */
+#define	LM80_TEMP_OS_STAT	(1<<0)	/* mirrors the state of RST_OUT#/OS# */
+#define LM80_TEMP_OS_POL	(1<<1)	/* select OS# polarity */
+#define LM80_TEMP_OS_MODE	(1<<2)	/* selects Interrupt mode */
+#define LM80_TEMP_RES		(1<<3)	/* selects 9 or 11 bit temp resulution*/
+#define LM80_TEMP_LSB		(0xf<<4)/* 4 LSBs of 11 bit temp data */
+#define LM80_TEMP_LSB_9		(1<<7)	/* LSB of 9 bit temperature data */
+
+	/* 0x07 - 0x1f reserved	*/
+/*	LM80_VT0_IN		current Voltage 0 value */
+/*	LM80_VT1_IN		current Voltage 1 value */
+/*	LM80_VT2_IN		current Voltage 2 value */
+/*	LM80_VT3_IN		current Voltage 3 value */
+/*	LM80_VT4_IN		current Voltage 4 value */
+/*	LM80_VT5_IN		current Voltage 5 value */
+/*	LM80_VT6_IN		current Voltage 6 value */
+/*	LM80_TEMP_IN		current temperature value */
+/*	LM80_FAN1_IN		current Fan 1 count */
+/*	LM80_FAN2_IN		current Fan 2 count */
+/*	LM80_VT0_HIGH_LIM	high limit val for Voltage 0 */
+/*	LM80_VT0_LOW_LIM	low limit val for Voltage 0 */
+/*	LM80_VT1_HIGH_LIM	high limit val for Voltage 1 */
+/*	LM80_VT1_LOW_LIM	low limit val for Voltage 1 */
+/*	LM80_VT2_HIGH_LIM	high limit val for Voltage 2 */
+/*	LM80_VT2_LOW_LIM	low limit val for Voltage 2 */
+/*	LM80_VT3_HIGH_LIM	high limit val for Voltage 3 */
+/*	LM80_VT3_LOW_LIM	low limit val for Voltage 3 */
+/*	LM80_VT4_HIGH_LIM	high limit val for Voltage 4 */
+/*	LM80_VT4_LOW_LIM	low limit val for Voltage 4 */
+/*	LM80_VT5_HIGH_LIM	high limit val for Voltage 5 */
+/*	LM80_VT5_LOW_LIM	low limit val for Voltage 5 */
+/*	LM80_VT6_HIGH_LIM	high limit val for Voltage 6 */
+/*	LM80_VT6_LOW_LIM	low limit val for Voltage 6 */
+/*	LM80_THOT_LIM_UP	hot temperature limit (high) */
+/*	LM80_THOT_LIM_LO	hot temperature limit (low) */
+/*	LM80_TOS_LIM_UP		OS temperature limit (high) */
+/*	LM80_TOS_LIM_LO		OS temperature limit (low) */
+/*	LM80_FAN1_COUNT_LIM	Fan 1 count limit (high) */
+/*	LM80_FAN2_COUNT_LIM	Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+#define LM80_ADDR		0x28	/* LM80 default addr */
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_LM80_H */
diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h
new file mode 100644
index 0000000..711f873
--- /dev/null
+++ b/drivers/net/sk98lin/h/skaddr.h
@@ -0,0 +1,425 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 2002/11/15 07:24:42 $
+ * Purpose:	Header file for Address Management (MC, UC, Prom).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skaddr.h,v $
+ *	Revision 1.26  2002/11/15 07:24:42  tschilli
+ *	SK_ADDR_EQUAL macro fixed.
+ *
+ *	Revision 1.25  2002/06/10 13:55:18  tschilli
+ *	Changes for handling YUKON.
+ *	All changes are internally and not visible to the programmer
+ *	using this module.
+ *
+ *	Revision 1.24  2001/01/22 13:41:34  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.23  2000/08/10 11:27:50  rassmann
+ *	Editorial changes.
+ *	Preserving 32-bit alignment in structs for the adapter context.
+ *
+ *	Revision 1.22  2000/08/07 11:10:40  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.21  2000/05/04 09:39:59  rassmann
+ *	Editorial changes.
+ *	Corrected multicast address hashing.
+ *
+ *	Revision 1.20  1999/11/22 13:46:14  cgoos
+ *	Changed license header to GPL.
+ *	Allowing overwrite for SK_ADDR_EQUAL.
+ *
+ *	Revision 1.19  1999/05/28 10:56:07  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.18  1999/04/06 17:22:04  rassmann
+ *	Added private "ActivePort".
+ *
+ *	Revision 1.17  1999/01/14 16:18:19  rassmann
+ *	Corrected multicast initialization.
+ *
+ *	Revision 1.16  1999/01/04 10:30:36  rassmann
+ *	SkAddrOverride only possible after SK_INIT_IO phase.
+ *
+ *	Revision 1.15  1998/12/29 13:13:11  rassmann
+ *	An address override is now preserved in the SK_INIT_IO phase.
+ *	All functions return an int now.
+ *	Extended parameter checking.
+ *
+ *	Revision 1.14  1998/11/24 12:39:45  rassmann
+ *	Reserved multicast entry for BPDU address.
+ *	13 multicast entries left for protocol.
+ *
+ *	Revision 1.13  1998/11/13 17:24:32  rassmann
+ *	Changed return value of SkAddrOverride to int.
+ *
+ *	Revision 1.12  1998/11/13 16:56:19  rassmann
+ *	Added macro SK_ADDR_COMPARE.
+ *	Changed return type of SkAddrOverride to SK_BOOL.
+ *
+ *	Revision 1.11  1998/10/28 18:16:35  rassmann
+ *	Avoiding I/Os before SK_INIT_RUN level.
+ *	Aligning InexactFilter.
+ *
+ *	Revision 1.10  1998/10/22 11:39:10  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *
+ *	Revision 1.9  1998/10/15 15:15:49  rassmann
+ *	Changed Flags Parameters from SK_U8 to int.
+ *	Checked with lint.
+ *
+ *	Revision 1.8  1998/09/24 19:15:12  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.7  1998/09/18 20:22:13  rassmann
+ *	Added HW access.
+ *
+ *	Revision 1.6  1998/09/04 19:40:20  rassmann
+ *	Interface enhancements.
+ *
+ *	Revision 1.5  1998/09/04 12:40:57  rassmann
+ *	Interface cleanup.
+ *
+ *	Revision 1.4  1998/09/04 12:14:13  rassmann
+ *	Interface cleanup.
+ *
+ *	Revision 1.3  1998/09/02 16:56:40  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.2  1998/08/27 14:26:09  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.1  1998/08/21 08:31:08  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses and promiscuous mode
+ * on GEnesis adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKADDR_H
+#define __INC_SKADDR_H
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_MAC_ADDR_LEN				6	/* Length of MAC address. */
+#define	SK_MAX_ADDRS				14	/* #Addrs for exact match. */
+
+/* ----- Common return values ----- */
+
+#define SK_ADDR_SUCCESS				0	/* Function returned successfully. */
+#define SK_ADDR_ILLEGAL_PORT			100	/* Port number too high. */
+#define SK_ADDR_TOO_EARLY			101	/* Function called too early. */
+
+/* ----- Clear/Add flag bits ----- */
+
+#define SK_ADDR_PERMANENT			1	/* RLMT Address */
+
+/* ----- Additional Clear flag bits ----- */
+
+#define SK_MC_SW_ONLY				2	/* Do not update HW when clearing. */
+
+/* ----- Override flag bits ----- */
+
+#define SK_ADDR_LOGICAL_ADDRESS		0
+#define SK_ADDR_VIRTUAL_ADDRESS		(SK_ADDR_LOGICAL_ADDRESS)	/* old */
+#define SK_ADDR_PHYSICAL_ADDRESS	1
+#define SK_ADDR_CLEAR_LOGICAL		2
+#define SK_ADDR_SET_LOGICAL			4
+
+/* ----- Override return values ----- */
+
+#define SK_ADDR_OVERRIDE_SUCCESS	(SK_ADDR_SUCCESS)
+#define SK_ADDR_DUPLICATE_ADDRESS	1
+#define SK_ADDR_MULTICAST_ADDRESS	2
+
+/* ----- Partitioning of excact match table ----- */
+
+#define SK_ADDR_EXACT_MATCHES		16	/* #Exact match entries. */
+
+#define SK_ADDR_FIRST_MATCH_RLMT	1
+#define SK_ADDR_LAST_MATCH_RLMT		2
+#define SK_ADDR_FIRST_MATCH_DRV		3
+#define SK_ADDR_LAST_MATCH_DRV		(SK_ADDR_EXACT_MATCHES - 1)
+
+/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */
+
+#define SK_MC_FILTERING_EXACT		0	/* Exact filtering. */
+#define SK_MC_FILTERING_INEXACT		1	/* Inexact filtering. */
+
+/* ----- Additional SkAddrMcAdd return values ----- */
+
+#define SK_MC_ILLEGAL_ADDRESS		2	/* Illegal address. */
+#define SK_MC_ILLEGAL_PORT			3	/* Illegal port (not the active one). */
+#define SK_MC_RLMT_OVERFLOW			4	/* Too many RLMT mc addresses. */
+
+/* Promiscuous mode bits ----- */
+
+#define SK_PROM_MODE_NONE			0	/* Normal receive. */
+#define SK_PROM_MODE_LLC			1	/* Receive all LLC frames. */
+#define SK_PROM_MODE_ALL_MC			2	/* Receive all multicast frames. */
+/* #define SK_PROM_MODE_NON_LLC		4 */	/* Receive all non-LLC frames. */
+
+/* Macros */
+
+#if 0
+#ifndef SK_ADDR_EQUAL
+/*
+ * "&" instead of "&&" allows better optimization on IA-64.
+ * The replacement is safe here, as all bytes exist.
+ */
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+	(((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+	(((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+	(((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+	(((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+	(((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif	/* SK_ADDR_EQUAL */
+#endif /* 0 */
+
+#ifndef SK_ADDR_EQUAL
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+	(((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+	(((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+	(((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+	(((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+	(((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(*(SK_U16 *)&(((SK_U8 *)(A1))[4]) == *(SK_U16 *)&(((SK_U8 *)(A2))[4])) && \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif	/* SK_ADDR_EQUAL */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_MacAddr {
+	SK_U8	a[SK_MAC_ADDR_LEN];
+} SK_MAC_ADDR;
+
+
+/* SK_FILTER is used to ensure alignment of the filter. */
+typedef union s_InexactFilter {
+	SK_U8	Bytes[8];
+	SK_U64	Val;	/* Dummy entry for alignment only. */
+} SK_FILTER64;
+
+
+typedef struct s_AddrNet SK_ADDR_NET;
+
+
+typedef struct s_AddrPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR	CurrentMacAddress;	/* Current physical MAC Address. */
+	SK_MAC_ADDR	PermanentMacAddress;	/* Permanent physical MAC Address. */
+	int		PromMode;		/* Promiscuous Mode. */
+
+/* ----- Private part ----- */
+
+	SK_MAC_ADDR	PreviousMacAddress;	/* Prev. phys. MAC Address. */
+	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U8		Align01;
+
+	SK_U32		FirstExactMatchRlmt;
+	SK_U32		NextExactMatchRlmt;
+	SK_U32		FirstExactMatchDrv;
+	SK_U32		NextExactMatchDrv;
+	SK_MAC_ADDR	Exact[SK_ADDR_EXACT_MATCHES];
+	SK_FILTER64	InexactFilter;			/* For 64-bit hash register. */
+	SK_FILTER64	InexactRlmtFilter;		/* For 64-bit hash register. */
+	SK_FILTER64	InexactDrvFilter;		/* For 64-bit hash register. */
+} SK_ADDR_PORT;
+
+
+struct s_AddrNet {
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR		CurrentMacAddress;	/* Logical MAC Address. */
+	SK_MAC_ADDR		PermanentMacAddress;	/* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+	SK_U32			ActivePort;		/* View of module ADDR. */
+	SK_BOOL			CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U8			Align01;
+	SK_U16			Align02;
+};
+
+
+typedef struct s_Addr {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_ADDR_NET		Net[SK_MAX_NETS];
+	SK_ADDR_PORT	Port[SK_MAX_MACS];
+
+/* ----- Private part ----- */
+} SK_ADDR;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkAddr */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	int	SkAddrInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int	Level);
+
+extern	int	SkAddrMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
+
+extern	int	SkAddrXmacMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
+
+extern	int	SkAddrGmacMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
+
+extern	int	SkAddrMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrXmacMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrGmacMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
+extern	int	SkAddrXmacMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
+extern	int	SkAddrGmacMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
+extern	int	SkAddrOverride(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pNewAddr,
+	int		Flags);
+
+extern	int	SkAddrPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);
+
+extern	int	SkAddrXmacPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);
+
+extern	int	SkAddrGmacPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);
+
+extern	int	SkAddrSwap(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	FromPortNumber,
+	SK_U32	ToPortNumber);
+
+#else	/* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style prototypes are not yet provided.
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKADDR_H */
diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h
new file mode 100644
index 0000000..2acae32
--- /dev/null
+++ b/drivers/net/sk98lin/h/skcsum.h
@@ -0,0 +1,261 @@
+/******************************************************************************
+ *
+ * Name:	skcsum.h
+ * Project:	GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 2001/02/06 11:21:39 $
+ * Purpose:	Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skcsum.h,v $
+ *	Revision 1.9  2001/02/06 11:21:39  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.8  2001/02/06 11:15:36  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.7  2000/06/29 13:17:05  rassmann
+ *	Corrected reception of a packet with UDP checksum == 0 (which means there
+ *	is no UDP checksum).
+ *
+ *	Revision 1.6  2000/02/28 12:33:44  cgoos
+ *	Changed C++ style comments to C style.
+ *
+ *	Revision 1.5  2000/02/21 12:10:05  cgoos
+ *	Fixed license comment.
+ *
+ *	Revision 1.4  2000/02/21 11:08:37  cgoos
+ *	Merged changes back into common source.
+ *
+ *	Revision 1.1  1999/07/26 14:47:49  mkarl
+ *	changed from common source to windows specific source
+ *	added return SKCS_STATUS_IP_CSUM_ERROR_UDP and
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester
+ *	changes for Tx csum offload
+ *
+ *	Revision 1.2  1998/09/04 12:16:34  mhaveman
+ *	Checked in for Stephan to allow compilation.
+ *	-Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic
+ *	-Added prototype for SkCsEvent()
+ *
+ *	Revision 1.1  1998/09/01 15:36:53  swolf
+ *	initial revision
+ *
+ *	01-Sep-1998 sw	Created.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * Public header file for the "GEnesis" common module "CSUM".
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *	SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *	empty module.
+ *
+ *	SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *	definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *	external.
+ *
+ *	SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *	definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *	external.
+ *
+ * Include File Hierarchy:
+ *
+ *	"h/skcsum.h"
+ *	 "h/sktypes.h"
+ *	 "h/skqueue.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKCSUM_H
+#define __INC_SKCSUM_H
+
+#include "h/sktypes.h"
+#include "h/skqueue.h"
+
+/* defines ********************************************************************/
+
+/*
+ * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags'  if no user
+ * overwrite.
+ */
+#ifndef SKCS_OVERWRITE_PROTO	/* User overwrite? */
+#define SKCS_PROTO_IP	0x1	/* IP (Internet Protocol version 4) */
+#define SKCS_PROTO_TCP	0x2	/* TCP (Transmission Control Protocol) */
+#define SKCS_PROTO_UDP	0x4	/* UDP (User Datagram Protocol) */
+
+/* Indices for protocol statistics. */
+#define SKCS_PROTO_STATS_IP	0
+#define SKCS_PROTO_STATS_UDP	1
+#define SKCS_PROTO_STATS_TCP	2
+#define SKCS_NUM_PROTOCOLS	3	/* Number of supported protocols. */
+#endif	/* !SKCS_OVERWRITE_PROTO */
+
+/*
+ * Define the default SKCS_STATUS type and values if no user overwrite.
+ *
+ *	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
+ *	SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *	SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *	SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *	SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *	SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *	SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ *	SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum.
+ */
+#ifndef SKCS_OVERWRITE_STATUS	/* User overwrite? */
+#define SKCS_STATUS	int	/* Define status type. */
+
+#define SKCS_STATUS_UNKNOWN_IP_VERSION	1
+#define SKCS_STATUS_IP_CSUM_ERROR		2
+#define SKCS_STATUS_IP_FRAGMENT			3
+#define SKCS_STATUS_IP_CSUM_OK			4
+#define SKCS_STATUS_TCP_CSUM_ERROR		5
+#define SKCS_STATUS_UDP_CSUM_ERROR		6
+#define SKCS_STATUS_TCP_CSUM_OK			7
+#define SKCS_STATUS_UDP_CSUM_OK			8
+/* needed for Microsoft */
+#define SKCS_STATUS_IP_CSUM_ERROR_UDP	9
+#define SKCS_STATUS_IP_CSUM_ERROR_TCP	10
+/* UDP checksum may be omitted */
+#define SKCS_STATUS_IP_CSUM_OK_NO_UDP	11
+#endif	/* !SKCS_OVERWRITE_STATUS */
+
+/* Clear protocol statistics event. */
+#define SK_CSUM_EVENT_CLEAR_PROTO_STATS	1
+
+/*
+ * Add two values in one's complement.
+ *
+ * Note: One of the two input values may be "longer" than 16-bit, but then the
+ * resulting sum may be 17 bits long. In this case, add zero to the result using
+ * SKCS_OC_ADD() again.
+ *
+ *	Result = Value1 + Value2
+ */
+#define SKCS_OC_ADD(Result, Value1, Value2) {				\
+	unsigned long Sum;						\
+									\
+	Sum = (unsigned long) (Value1) + (unsigned long) (Value2);	\
+	/* Add-in any carry. */						\
+	(Result) = (Sum & 0xffff) + (Sum >> 16);			\
+}
+
+/*
+ * Subtract two values in one's complement.
+ *
+ *	Result = Value1 - Value2
+ */
+#define SKCS_OC_SUB(Result, Value1, Value2)	\
+	SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff)
+
+/* typedefs *******************************************************************/
+
+/*
+ * SKCS_PROTO_STATS - The CSUM protocol statistics structure.
+ *
+ * There is one instance of this structure for each protocol supported.
+ */
+typedef struct s_CsProtocolStatistics {
+	SK_U64 RxOkCts;		/* Receive checksum ok. */
+	SK_U64 RxUnableCts;	/* Unable to verify receive checksum. */
+	SK_U64 RxErrCts;	/* Receive checksum error. */
+	SK_U64 TxOkCts;		/* Transmit checksum ok. */
+	SK_U64 TxUnableCts;	/* Unable to calculate checksum in hw. */
+} SKCS_PROTO_STATS;
+
+/*
+ * s_Csum - The CSUM module context structure.
+ */
+typedef struct s_Csum {
+	/* Enabled receive SK_PROTO_XXX bit flags. */
+	unsigned ReceiveFlags[SK_MAX_NETS];
+#ifdef TX_CSUM
+	unsigned TransmitFlags[SK_MAX_NETS];
+#endif /* TX_CSUM */
+
+	/* The protocol statistics structure; one per supported protocol. */
+	SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS];
+} SK_CSUM;
+
+/*
+ * SKCS_PACKET_INFO - The packet information structure.
+ */
+typedef struct s_CsPacketInfo {
+	/* Bit field specifiying the desired/found protocols. */
+	unsigned ProtocolFlags;
+
+	/* Length of complete IP header, including any option fields. */
+	unsigned IpHeaderLength;
+
+	/* IP header checksum. */
+	unsigned IpHeaderChecksum;
+
+	/* TCP/UDP pseudo header checksum. */
+	unsigned PseudoHeaderChecksum;
+} SKCS_PACKET_INFO;
+
+/* function prototypes ********************************************************/
+
+#ifndef SkCsCalculateChecksum
+extern unsigned SkCsCalculateChecksum(
+	void		*pData,
+	unsigned	Length);
+#endif
+
+extern int SkCsEvent(
+	SK_AC		*pAc,
+	SK_IOC		Ioc,
+	SK_U32		Event,
+	SK_EVPARA	Param);
+
+extern SKCS_STATUS SkCsGetReceiveInfo(
+	SK_AC		*pAc,
+	void		*pIpHeader,
+	unsigned	Checksum1,
+	unsigned	Checksum2,
+	int			NetNumber);
+
+extern void SkCsGetSendInfo(
+	SK_AC				*pAc,
+	void				*pIpHeader,
+	SKCS_PACKET_INFO	*pPacketInfo,
+	int					NetNumber);
+
+extern void SkCsSetReceiveFlags(
+	SK_AC		*pAc,
+	unsigned	ReceiveFlags,
+	unsigned	*pChecksum1Offset,
+	unsigned	*pChecksum2Offset,
+	int			NetNumber);
+
+#endif	/* __INC_SKCSUM_H */
diff --git a/drivers/net/sk98lin/h/skdebug.h b/drivers/net/sk98lin/h/skdebug.h
new file mode 100644
index 0000000..cf5b5ad
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdebug.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Name:	skdebug.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 2002/07/15 15:37:13 $
+ * Purpose:	SK specific DEBUG support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skdebug.h,v $
+ *	Revision 1.12  2002/07/15 15:37:13  rschmidt
+ *	Power Management support
+ *	Editorial changes
+ *
+ *	Revision 1.11  2002/04/25 11:04:39  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.10  1999/11/22 13:47:40  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.9  1999/09/14 14:02:43  rwahl
+ *	Added SK_DBGMOD_PECP.
+ *
+ *	Revision 1.8  1998/11/25 08:31:54  gklug
+ *	fix: no C++ comments allowed in common sources
+ *
+ *	Revision 1.7  1998/11/24 16:47:24  swolf
+ *	Driver may now define its own SK_DBG_MSG() (eg. in "h/skdrv1st.h").
+ *
+ *	Revision 1.6  1998/10/28 10:23:55  rassmann
+ *	ADDED SK_DBGMOD_ADDR.
+ *
+ *	Revision 1.5  1998/10/22 09:43:55  gklug
+ *	add: CSUM module
+ *
+ *	Revision 1.4  1998/10/01 07:54:44  gklug
+ *	add: PNMI debug module
+ *
+ *	Revision 1.3  1998/09/18 08:32:34  afischer
+ *	Macros changed according ssr-spec.:
+ *		SK_DBG_MODCHK -> SK_DBG_CHKMOD
+ *		SK_DBG_CATCHK -> SK_DBG_CHKCAT
+ *
+ *	Revision 1.2  1998/07/03 14:38:25  malthoff
+ *	Add category SK_DBGCAT_FATAL.
+ *
+ *	Revision 1.1  1998/06/19 13:39:01  malthoff
+ *	created.
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDEBUG_H
+#define __INC_SKDEBUG_H
+
+#ifdef	DEBUG
+#ifndef SK_DBG_MSG
+#define SK_DBG_MSG(pAC,comp,cat,arg) \
+		if ( ((comp) & SK_DBG_CHKMOD(pAC)) && 	\
+		      ((cat) & SK_DBG_CHKCAT(pAC)) ) { 	\
+			SK_DBG_PRINTF arg ;		\
+		}
+#endif
+#else
+#define SK_DBG_MSG(pAC,comp,lev,arg)
+#endif
+
+/* PLS NOTE:
+ * =========
+ * Due to any restrictions of kernel printf routines do not use other
+ * format identifiers as: %x %d %c %s .
+ * Never use any combined format identifiers such as: %lx %ld in your
+ * printf - argument (arg) because some OS specific kernel printfs may
+ * only support some basic identifiers.
+ */
+
+/* Debug modules */
+
+#define SK_DBGMOD_MERR	0x00000001L	/* general module error indication */
+#define SK_DBGMOD_HWM	0x00000002L	/* Hardware init module */
+#define SK_DBGMOD_RLMT	0x00000004L	/* RLMT module */
+#define SK_DBGMOD_VPD	0x00000008L	/* VPD module */
+#define SK_DBGMOD_I2C	0x00000010L	/* I2C module */
+#define SK_DBGMOD_PNMI	0x00000020L	/* PNMI module */
+#define SK_DBGMOD_CSUM	0x00000040L	/* CSUM module */
+#define SK_DBGMOD_ADDR	0x00000080L	/* ADDR module */
+#define SK_DBGMOD_PECP	0x00000100L	/* PECP module */
+#define SK_DBGMOD_POWM	0x00000200L	/* Power Management module */
+
+/* Debug events */
+
+#define SK_DBGCAT_INIT	0x00000001L	/* module/driver initialization */
+#define SK_DBGCAT_CTRL	0x00000002L	/* controlling devices */
+#define SK_DBGCAT_ERR	0x00000004L	/* error handling paths */
+#define SK_DBGCAT_TX	0x00000008L	/* transmit path */
+#define SK_DBGCAT_RX	0x00000010L	/* receive path */
+#define SK_DBGCAT_IRQ	0x00000020L	/* general IRQ handling */
+#define SK_DBGCAT_QUEUE	0x00000040L	/* any queue management */
+#define SK_DBGCAT_DUMP	0x00000080L	/* large data output e.g. hex dump */
+#define SK_DBGCAT_FATAL	0x00000100L	/* fatal error */
+
+#endif	/* __INC_SKDEBUG_H */
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
new file mode 100644
index 0000000..af34d7b
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ * Name:	skdrv1st.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.11 $
+ * Date:	$Date: 2003/02/25 14:16:40 $
+ * Purpose:	First header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skdrv1st.h,v $
+ *	Revision 1.11  2003/02/25 14:16:40  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.10  2002/10/02 12:46:02  mlindner
+ *	Add: Support for Yukon
+ *
+ *	Revision 1.9.2.2  2001/12/07 12:06:42  mlindner
+ *	Fix: malloc -> slab changes
+ *
+ *	Revision 1.9.2.1  2001/03/12 16:50:59  mlindner
+ *	chg: kernel 2.4 adaption
+ *
+ *	Revision 1.9  2001/01/22 14:16:04  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *
+ *	Revision 1.8  2000/02/21 12:19:18  cgoos
+ *	Added default for SK_DEBUG_CHKMOD/_CHKCAT
+ *
+ *	Revision 1.7  1999/11/22 13:50:00  cgoos
+ *	Changed license header to GPL.
+ *	Added overwrite for several functions.
+ *	Removed linux 2.0.x definitions.
+ *	Removed PCI vendor ID definition (now in kernel).
+ *
+ *	Revision 1.6  1999/07/27 08:03:33  cgoos
+ *	Changed SK_IN/OUT macros to readX/writeX instead of memory
+ *	accesses (necessary for ALPHA).
+ *
+ *	Revision 1.5  1999/07/23 12:10:21  cgoos
+ *	Removed SK_RLMT_SLOW_LOOKAHEAD define.
+ *
+ *	Revision 1.4  1999/07/14 12:31:13  cgoos
+ *	Added SK_RLMT_SLOW_LOOKAHEAD define.
+ *
+ *	Revision 1.3  1999/04/07 10:12:54  cgoos
+ *	Added check for KERNEL and OPTIMIZATION defines.
+ *
+ *	Revision 1.2  1999/03/01 08:51:47  cgoos
+ *	Fixed pcibios_read/write definitions.
+ *
+ *	Revision 1.1  1999/02/16 07:40:49  cgoos
+ *	First version.
+ *
+ *
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the first include file of the driver, which includes all
+ * neccessary system header files and some of the GEnesis header files.
+ * It also defines some basic items.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+#if 0
+/* Check kernel version */
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE > 0x020300)
+#endif
+#endif
+
+typedef struct s_AC	SK_AC;
+
+/* override some default functions with optimized linux functions */
+
+#define SK_PNMI_STORE_U16(p,v)		memcpy((char*)(p),(char*)&(v),2)
+#define SK_PNMI_STORE_U32(p,v)		memcpy((char*)(p),(char*)&(v),4)
+#define SK_PNMI_STORE_U64(p,v)		memcpy((char*)(p),(char*)&(v),8)
+#define SK_PNMI_READ_U16(p,v)		memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U32(p,v)		memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U64(p,v)		memcpy((char*)&(v),(char*)(p),2)
+
+#define SkCsCalculateChecksum(p,l)	((~ip_compute_csum(p, l)) & 0xffff)
+
+#define SK_ADDR_EQUAL(a1,a2)		(!memcmp(a1,a2,6))
+
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#if 0
+#include <linux/version.h>
+#endif
+#include <linux/types.h>
+#if 0
+#include <linux/kernel.h>
+#endif
+#include <linux/string.h>
+#if 0
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#if 0
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+#endif
+
+#include	"h/sktypes.h"
+#include	"h/skerror.h"
+#include	"h/skdebug.h"
+#include	"h/lm80.h"
+#include	"h/xmac_ii.h"
+
+#include "u-boot_compat.h"
+
+#ifdef __LITTLE_ENDIAN
+#define SK_LITTLE_ENDIAN
+#else
+#define SK_BIG_ENDIAN
+#endif
+
+#if 0
+#define SK_NET_DEVICE	net_device
+#else
+#define SK_NET_DEVICE	eth_device
+#endif
+
+
+/* we use gethrtime(), return unit: nanoseconds */
+#if 0
+#define SK_TICKS_PER_SEC	HZ
+#else
+#define SK_TICKS_PER_SEC	CFG_HZ
+#endif
+
+#define	SK_MEM_MAPPED_IO
+
+/* #define SK_RLMT_SLOW_LOOKAHEAD */
+
+#define SK_MAX_MACS		2
+#define SK_MAX_NETS		2
+
+#define SK_IOC			char*
+
+typedef struct s_DrvRlmtMbuf SK_MBUF;
+
+#define	SK_CONST64	INT64_C
+#define	SK_CONSTU64	UINT64_C
+
+#define SK_MEMCPY(dest,src,size)	memcpy(dest,src,size)
+#define SK_MEMCMP(s1,s2,size)		memcmp(s1,s2,size)
+#define SK_MEMSET(dest,val,size)	memset(dest,val,size)
+#define SK_STRLEN(pStr)			strlen((char*)(pStr))
+#define SK_STRNCPY(pDest,pSrc,size)	strncpy((char*)(pDest),(char*)(pSrc),size)
+#define SK_STRCMP(pStr1,pStr2)		strcmp((char*)(pStr1),(char*)(pStr2))
+
+/* macros to access the adapter */
+#define SK_OUT8(b,a,v)		writeb((v), ((b)+(a)))
+#define SK_OUT16(b,a,v)		writew((v), ((b)+(a)))
+#define SK_OUT32(b,a,v)		writel((v), ((b)+(a)))
+#define SK_IN8(b,a,pv)		(*(pv) = readb((b)+(a)))
+#define SK_IN16(b,a,pv)		(*(pv) = readw((b)+(a)))
+#define SK_IN32(b,a,pv)		(*(pv) = readl((b)+(a)))
+
+#define int8_t		char
+#define int16_t		short
+#define int32_t		long
+#define int64_t		long long
+#define uint8_t		u_char
+#define uint16_t	u_short
+#define uint32_t	u_long
+#define uint64_t	unsigned long long
+#define t_scalar_t	int
+#define t_uscalar_t	unsigned int
+#define uintptr_t	unsigned long
+
+#define __CONCAT__(A,B) A##B
+
+#define INT32_C(a)		__CONCAT__(a,L)
+#define INT64_C(a)		__CONCAT__(a,LL)
+#define UINT32_C(a)		__CONCAT__(a,UL)
+#define UINT64_C(a)		__CONCAT__(a,ULL)
+
+#ifdef DEBUG
+#define SK_DBG_PRINTF		printk
+#ifndef SK_DEBUG_CHKMOD
+#define SK_DEBUG_CHKMOD		0
+#endif
+#ifndef SK_DEBUG_CHKCAT
+#define SK_DEBUG_CHKCAT		0
+#endif
+/* those come from the makefile */
+#define SK_DBG_CHKMOD(pAC)	(SK_DEBUG_CHKMOD)
+#define SK_DBG_CHKCAT(pAC)	(SK_DEBUG_CHKCAT)
+
+extern void SkDbgPrintf(const char *format,...);
+
+#define SK_DBGMOD_DRV			0x00010000
+
+/**** possible driver debug categories ********************************/
+#define SK_DBGCAT_DRV_ENTRY		0x00010000
+#define SK_DBGCAT_DRV_SAP		0x00020000
+#define SK_DBGCAT_DRV_MCA		0x00040000
+#define SK_DBGCAT_DRV_TX_PROGRESS	0x00080000
+#define SK_DBGCAT_DRV_RX_PROGRESS	0x00100000
+#define SK_DBGCAT_DRV_PROGRESS		0x00200000
+#define SK_DBGCAT_DRV_MSG		0x00400000
+#define SK_DBGCAT_DRV_PROM		0x00800000
+#define SK_DBGCAT_DRV_TX_FRAME		0x01000000
+#define SK_DBGCAT_DRV_ERROR		0x02000000
+#define SK_DBGCAT_DRV_INT_SRC		0x04000000
+#define SK_DBGCAT_DRV_EVENT		0x08000000
+
+#endif
+
+#define SK_ERR_LOG		SkErrorLog
+
+extern void SkErrorLog(SK_AC*, int, int, char*);
+
+#endif
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h
new file mode 100644
index 0000000..a311827
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv2nd.h
@@ -0,0 +1,561 @@
+/******************************************************************************
+ *
+ * Name:	skdrv2nd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.15 $
+ * Date:	$Date: 2003/02/25 14:16:40 $
+ * Purpose:	Second header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skdrv2nd.h,v $
+ *	Revision 1.15  2003/02/25 14:16:40  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.14  2003/02/25 13:26:26  mlindner
+ *	Add: Support for various vendors
+ *
+ *	Revision 1.13  2002/10/02 12:46:02  mlindner
+ *	Add: Support for Yukon
+ *
+ *	Revision 1.12.2.2  2001/09/05 12:14:50  mlindner
+ *	add: New hardware revision int
+ *
+ *	Revision 1.12.2.1  2001/03/12 16:50:59  mlindner
+ *	chg: kernel 2.4 adaption
+ *
+ *	Revision 1.12  2001/03/01 12:52:15  mlindner
+ *	Fixed ring size
+ *
+ *	Revision 1.11  2001/02/19 13:28:02  mlindner
+ *	Changed PNMI parameter values
+ *
+ *	Revision 1.10  2001/01/22 14:16:04  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *
+ *	Revision 1.1  2000/10/05 19:46:50  phargrov
+ *	Add directory src/vipk_devs_nonlbl/vipk_sk98lin/
+ *	This is the SysKonnect SK-98xx Gigabit Ethernet driver,
+ *	contributed by SysKonnect.
+ *
+ *	Revision 1.9  2000/02/21 10:39:55  cgoos
+ *	Added flag for jumbo support usage.
+ *
+ *	Revision 1.8  1999/11/22 13:50:44  cgoos
+ *	Changed license header to GPL.
+ *	Fixed two comments.
+ *
+ *	Revision 1.7  1999/09/28 12:38:21  cgoos
+ *	Added CheckQueue to SK_AC.
+ *
+ *	Revision 1.6  1999/07/27 08:04:05  cgoos
+ *	Added checksumming variables to SK_AC.
+ *
+ *	Revision 1.5  1999/03/29 12:33:26  cgoos
+ *	Rreversed to fine lock granularity.
+ *
+ *	Revision 1.4  1999/03/15 12:14:02  cgoos
+ *	Added DriverLock to SK_AC.
+ *	Removed other locks.
+ *
+ *	Revision 1.3  1999/03/01 08:52:27  cgoos
+ *	Changed pAC->PciDev declaration.
+ *
+ *	Revision 1.2  1999/02/18 10:57:14  cgoos
+ *	Removed SkDrvTimeStamp prototype.
+ *	Fixed SkGeOsGetTime prototype.
+ *
+ *	Revision 1.1  1999/02/16 07:41:01  cgoos
+ *	First version.
+ *
+ *
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the second include file of the driver, which includes all other
+ * neccessary files and defines all structures and constants used by the
+ * driver and the common modules.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "h/skqueue.h"
+#include "h/skgehwt.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skgepnmi.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skaddr.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skrlmt.h"
+#include "h/skgedrv.h"
+
+#define SK_PCI_ISCOMPLIANT(result, pdev) {     \
+    result = SK_FALSE; /* default */     \
+    /* 3Com (0x10b7) */     \
+    if (pdev->vendor == 0x10b7) {     \
+	/* Gigabit Ethernet Adapter (0x1700) */     \
+	if ((pdev->device == 0x1700)) { \
+	    result = SK_TRUE;     \
+	}     \
+    /* SysKonnect (0x1148) */     \
+    } else if (pdev->vendor == 0x1148) {     \
+	/* SK-98xx Gigabit Ethernet Server Adapter (0x4300) */     \
+	/* SK-98xx V2 Gigabit Ethernet Adapter (0x4320) */     \
+	if ((pdev->device == 0x4300) || \
+	    (pdev->device == 0x4320)) { \
+	    result = SK_TRUE;     \
+	}     \
+    /* D-Link (0x1186) */     \
+    } else if (pdev->vendor == 0x1186) {     \
+	/* Gigabit Ethernet Adapter (0x4c00) */     \
+	if ((pdev->device == 0x4c00)) { \
+	    result = SK_TRUE;     \
+	}     \
+    /* CNet (0x1371) */     \
+    } else if (pdev->vendor == 0x1371) {     \
+	/* GigaCard Network Adapter (0x434e) */     \
+	if ((pdev->device == 0x434e)) { \
+	    result = SK_TRUE;     \
+	}     \
+    /* Linksys (0x1737) */     \
+    } else if (pdev->vendor == 0x1737) {     \
+	/* Gigabit Network Adapter (0x1032) */     \
+	/* Gigabit Network Adapter (0x1064) */     \
+	if ((pdev->device == 0x1032) || \
+	    (pdev->device == 0x1064)) { \
+	    result = SK_TRUE;     \
+	}     \
+    } else {     \
+	result = SK_FALSE;     \
+    }     \
+}
+
+
+extern SK_MBUF		*SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned);
+extern void		SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*);
+extern SK_U64		SkOsGetTime(SK_AC*);
+extern int		SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
+extern int		SkPciReadCfgWord(SK_AC*, int, SK_U16*);
+extern int		SkPciReadCfgByte(SK_AC*, int, SK_U8*);
+extern int		SkPciWriteCfgDWord(SK_AC*, int, SK_U32);
+extern int		SkPciWriteCfgWord(SK_AC*, int, SK_U16);
+extern int		SkPciWriteCfgByte(SK_AC*, int, SK_U8);
+extern int		SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
+
+struct s_DrvRlmtMbuf {
+	SK_MBUF		*pNext;		/* Pointer to next RLMT Mbuf. */
+	SK_U8		*pData;		/* Data buffer (virtually contig.). */
+	unsigned	Size;		/* Data buffer size. */
+	unsigned	Length;		/* Length of packet (<= Size). */
+	SK_U32		PortIdx;	/* Receiving/transmitting port. */
+#ifdef SK_RLMT_MBUF_PRIVATE
+	SK_RLMT_MBUF	Rlmt;		/* Private part for RLMT. */
+#endif  /* SK_RLMT_MBUF_PRIVATE */
+	struct sk_buff	*pOs;		/* Pointer to message block */
+};
+
+
+/*
+ * ioctl definitions
+ */
+#define		SK_IOCTL_BASE		(SIOCDEVPRIVATE)
+#define		SK_IOCTL_GETMIB		(SK_IOCTL_BASE + 0)
+#define		SK_IOCTL_SETMIB		(SK_IOCTL_BASE + 1)
+#define		SK_IOCTL_PRESETMIB	(SK_IOCTL_BASE + 2)
+
+typedef struct s_IOCTL	SK_GE_IOCTL;
+
+struct s_IOCTL {
+	char*		pData;
+	unsigned int	Len;
+};
+
+
+/*
+ * define sizes of descriptor rings in bytes
+ */
+
+#if 0
+#define		TX_RING_SIZE	(8*1024)
+#define		RX_RING_SIZE	(24*1024)
+#else
+#define		TX_RING_SIZE	(10 * 40)
+#define		RX_RING_SIZE	(10 * 40)
+#endif
+
+/*
+ * Buffer size for ethernet packets
+ */
+#define	ETH_BUF_SIZE	1540
+#define	ETH_MAX_MTU	1514
+#define ETH_MIN_MTU	60
+#define ETH_MULTICAST_BIT	0x01
+#define SK_JUMBO_MTU	9000
+
+/*
+ * transmit priority selects the queue: LOW=asynchron, HIGH=synchron
+ */
+#define TX_PRIO_LOW	0
+#define TX_PRIO_HIGH	1
+
+/*
+ * alignment of rx/tx descriptors
+ */
+#define DESCR_ALIGN	8
+
+/*
+ * definitions for pnmi. TODO
+ */
+#define SK_DRIVER_RESET(pAC, IoC)	0
+#define SK_DRIVER_SENDEVENT(pAC, IoC)	0
+#define SK_DRIVER_SELFTEST(pAC, IoC)	0
+/* For get mtu you must add an own function */
+#define SK_DRIVER_GET_MTU(pAc,IoC,i)	0
+#define SK_DRIVER_SET_MTU(pAc,IoC,i,v)	0
+#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v)	0
+
+
+/* TX and RX descriptors *****************************************************/
+
+typedef struct s_RxD RXD; /* the receive descriptor */
+
+struct s_RxD {
+	volatile SK_U32	RBControl;	/* Receive Buffer Control */
+	SK_U32		VNextRxd;	/* Next receive descriptor,low dword */
+	SK_U32		VDataLow;	/* Receive buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Receive buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Receive Frame Status word */
+	SK_U32		TimeStamp;	/* Time stamp from XMAC */
+	SK_U32		TcpSums;	/* TCP Sum 2 / TCP Sum 1 */
+	SK_U32		TcpSumStarts;	/* TCP Sum Start 2 / TCP Sum Start 1 */
+	RXD		*pNextRxd;	/* Pointer to next Rxd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+typedef struct s_TxD TXD; /* the transmit descriptor */
+
+struct s_TxD {
+	volatile SK_U32	TBControl;	/* Transmit Buffer Control */
+	SK_U32		VNextTxd;	/* Next transmit descriptor,low dword */
+	SK_U32		VDataLow;	/* Transmit Buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Transmit Buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Transmit Frame Status Word */
+	SK_U32		TcpSumOfs;	/* Reserved / TCP Sum Offset */
+	SK_U16		TcpSumSt;	/* TCP Sum Start */
+	SK_U16		TcpSumWr;	/* TCP Sum Write */
+	SK_U32		TcpReserved;	/* not used */
+	TXD		*pNextTxd;	/* Pointer to next Txd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+
+/* definition of flags in descriptor control field */
+#define	RX_CTRL_OWN_BMU 	UINT32_C(0x80000000)
+#define	RX_CTRL_STF		UINT32_C(0x40000000)
+#define	RX_CTRL_EOF		UINT32_C(0x20000000)
+#define	RX_CTRL_EOB_IRQ		UINT32_C(0x10000000)
+#define	RX_CTRL_EOF_IRQ		UINT32_C(0x08000000)
+#define RX_CTRL_DEV_NULL	UINT32_C(0x04000000)
+#define RX_CTRL_STAT_VALID	UINT32_C(0x02000000)
+#define RX_CTRL_TIME_VALID	UINT32_C(0x01000000)
+#define RX_CTRL_CHECK_DEFAULT	UINT32_C(0x00550000)
+#define RX_CTRL_CHECK_CSUM	UINT32_C(0x00560000)
+#define	RX_CTRL_LEN_MASK	UINT32_C(0x0000FFFF)
+
+#define	TX_CTRL_OWN_BMU 	UINT32_C(0x80000000)
+#define	TX_CTRL_STF		UINT32_C(0x40000000)
+#define	TX_CTRL_EOF		UINT32_C(0x20000000)
+#define	TX_CTRL_EOB_IRQ		UINT32_C(0x10000000)
+#define	TX_CTRL_EOF_IRQ		UINT32_C(0x08000000)
+#define TX_CTRL_ST_FWD		UINT32_C(0x04000000)
+#define TX_CTRL_DISAB_CRC	UINT32_C(0x02000000)
+#define TX_CTRL_SOFTWARE	UINT32_C(0x01000000)
+#define TX_CTRL_CHECK_DEFAULT	UINT32_C(0x00550000)
+#define TX_CTRL_CHECK_CSUM	UINT32_C(0x00560000)
+#define	TX_CTRL_LEN_MASK	UINT32_C(0x0000FFFF)
+
+
+/* The offsets of registers in the TX and RX queue control io area ***********/
+
+#define RX_Q_BUF_CTRL_CNT	0x00
+#define RX_Q_NEXT_DESCR_LOW	0x04
+#define RX_Q_BUF_ADDR_LOW	0x08
+#define RX_Q_BUF_ADDR_HIGH	0x0c
+#define RX_Q_FRAME_STAT		0x10
+#define RX_Q_TIME_STAMP		0x14
+#define RX_Q_CSUM_1_2		0x18
+#define RX_Q_CSUM_START_1_2	0x1c
+#define RX_Q_CUR_DESCR_LOW	0x20
+#define RX_Q_DESCR_HIGH		0x24
+#define RX_Q_CUR_ADDR_LOW	0x28
+#define RX_Q_CUR_ADDR_HIGH	0x2c
+#define RX_Q_CUR_BYTE_CNT	0x30
+#define RX_Q_CTRL		0x34
+#define RX_Q_FLAG		0x38
+#define RX_Q_TEST1		0x3c
+#define RX_Q_TEST2		0x40
+#define RX_Q_TEST3		0x44
+
+#define TX_Q_BUF_CTRL_CNT	0x00
+#define TX_Q_NEXT_DESCR_LOW	0x04
+#define TX_Q_BUF_ADDR_LOW	0x08
+#define TX_Q_BUF_ADDR_HIGH	0x0c
+#define TX_Q_FRAME_STAT		0x10
+#define TX_Q_CSUM_START		0x14
+#define TX_Q_CSUM_START_POS	0x18
+#define TX_Q_RESERVED		0x1c
+#define TX_Q_CUR_DESCR_LOW	0x20
+#define TX_Q_DESCR_HIGH		0x24
+#define TX_Q_CUR_ADDR_LOW	0x28
+#define TX_Q_CUR_ADDR_HIGH	0x2c
+#define TX_Q_CUR_BYTE_CNT	0x30
+#define TX_Q_CTRL		0x34
+#define TX_Q_FLAG		0x38
+#define TX_Q_TEST1		0x3c
+#define TX_Q_TEST2		0x40
+#define TX_Q_TEST3		0x44
+
+/* definition of flags in the queue control field */
+#define RX_Q_CTRL_POLL_ON	0x00000080
+#define RX_Q_CTRL_POLL_OFF	0x00000040
+#define RX_Q_CTRL_STOP		0x00000020
+#define RX_Q_CTRL_START		0x00000010
+#define RX_Q_CTRL_CLR_I_PAR	0x00000008
+#define RX_Q_CTRL_CLR_I_EOB	0x00000004
+#define RX_Q_CTRL_CLR_I_EOF	0x00000002
+#define RX_Q_CTRL_CLR_I_ERR	0x00000001
+
+#define TX_Q_CTRL_POLL_ON	0x00000080
+#define TX_Q_CTRL_POLL_OFF	0x00000040
+#define TX_Q_CTRL_STOP		0x00000020
+#define TX_Q_CTRL_START		0x00000010
+#define TX_Q_CTRL_CLR_I_EOB	0x00000004
+#define TX_Q_CTRL_CLR_I_EOF	0x00000002
+#define TX_Q_CTRL_CLR_I_ERR	0x00000001
+
+
+/* Interrupt bits in the interrupts source register **************************/
+#define IRQ_HW_ERROR		0x80000000
+#define IRQ_RESERVED		0x40000000
+#define IRQ_PKT_TOUT_RX1	0x20000000
+#define IRQ_PKT_TOUT_RX2	0x10000000
+#define IRQ_PKT_TOUT_TX1	0x08000000
+#define IRQ_PKT_TOUT_TX2	0x04000000
+#define IRQ_I2C_READY		0x02000000
+#define IRQ_SW			0x01000000
+#define IRQ_EXTERNAL_REG	0x00800000
+#define IRQ_TIMER		0x00400000
+#define IRQ_MAC1		0x00200000
+#define IRQ_LINK_SYNC_C_M1	0x00100000
+#define IRQ_MAC2		0x00080000
+#define IRQ_LINK_SYNC_C_M2	0x00040000
+#define IRQ_EOB_RX1		0x00020000
+#define IRQ_EOF_RX1		0x00010000
+#define IRQ_CHK_RX1		0x00008000
+#define IRQ_EOB_RX2		0x00004000
+#define IRQ_EOF_RX2		0x00002000
+#define IRQ_CHK_RX2		0x00001000
+#define IRQ_EOB_SY_TX1		0x00000800
+#define IRQ_EOF_SY_TX1		0x00000400
+#define IRQ_CHK_SY_TX1		0x00000200
+#define IRQ_EOB_AS_TX1		0x00000100
+#define IRQ_EOF_AS_TX1		0x00000080
+#define IRQ_CHK_AS_TX1		0x00000040
+#define IRQ_EOB_SY_TX2		0x00000020
+#define IRQ_EOF_SY_TX2		0x00000010
+#define IRQ_CHK_SY_TX2		0x00000008
+#define IRQ_EOB_AS_TX2		0x00000004
+#define IRQ_EOF_AS_TX2		0x00000002
+#define IRQ_CHK_AS_TX2		0x00000001
+
+#define DRIVER_IRQS	(IRQ_SW | IRQ_EOF_RX1 | IRQ_EOF_RX2 | \
+			IRQ_EOF_SY_TX1 | IRQ_EOF_AS_TX1 | \
+			IRQ_EOF_SY_TX2 | IRQ_EOF_AS_TX2)
+
+#define SPECIAL_IRQS	(IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \
+			IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \
+			IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \
+			IRQ_MAC1 | IRQ_LINK_SYNC_C_M1 | \
+			IRQ_MAC2 | IRQ_LINK_SYNC_C_M2 | \
+			IRQ_CHK_RX1 | IRQ_CHK_RX2 | \
+			IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \
+			IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2)
+
+#define IRQ_MASK	(IRQ_SW | IRQ_EOB_RX1 | IRQ_EOF_RX1 | \
+			IRQ_EOB_RX2 | IRQ_EOF_RX2 | \
+			IRQ_EOB_SY_TX1 | IRQ_EOF_SY_TX1 | \
+			IRQ_EOB_AS_TX1 | IRQ_EOF_AS_TX1 | \
+			IRQ_EOB_SY_TX2 | IRQ_EOF_SY_TX2 | \
+			IRQ_EOB_AS_TX2 | IRQ_EOF_AS_TX2 | \
+			IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \
+			IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \
+			IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \
+			IRQ_MAC1 | \
+			IRQ_MAC2 | \
+			IRQ_CHK_RX1 | IRQ_CHK_RX2 | \
+			IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \
+			IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2)
+
+#define IRQ_HWE_MASK	0x00000FFF /* enable all HW irqs */
+
+typedef struct s_DevNet DEV_NET;
+
+struct s_DevNet {
+	int             PortNr;
+	int             NetNr;
+	int             Mtu;
+	int             Up;
+	SK_AC   *pAC;
+};
+
+typedef struct s_TxPort		TX_PORT;
+
+struct s_TxPort {
+	/* the transmit descriptor rings */
+	caddr_t		pTxDescrRing;	/* descriptor area memory */
+	SK_U64		VTxDescrRing;	/* descr. area bus virt. addr. */
+	TXD		*pTxdRingHead;	/* Head of Tx rings */
+	TXD		*pTxdRingTail;	/* Tail of Tx rings */
+	TXD		*pTxdRingPrev;	/* descriptor sent previously */
+	int		TxdRingFree;	/* # of free entrys */
+#if 0
+	spinlock_t	TxDesRingLock;	/* serialize descriptor accesses */
+#endif
+	caddr_t		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+typedef struct s_RxPort		RX_PORT;
+
+struct s_RxPort {
+	/* the receive descriptor rings */
+	caddr_t		pRxDescrRing;	/* descriptor area memory */
+	SK_U64		VRxDescrRing;   /* descr. area bus virt. addr. */
+	RXD		*pRxdRingHead;	/* Head of Rx rings */
+	RXD		*pRxdRingTail;	/* Tail of Rx rings */
+	RXD		*pRxdRingPrev;	/* descriptor given to BMU previously */
+	int		RxdRingFree;	/* # of free entrys */
+#if 0
+	spinlock_t	RxDesRingLock;	/* serialize descriptor accesses */
+#endif
+	int		RxFillLimit;	/* limit for buffers in ring */
+	caddr_t		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+typedef struct s_PerStrm	PER_STRM;
+
+#define SK_ALLOC_IRQ	0x00000001
+
+/****************************************************************************
+ * Per board structure / Adapter Context structure:
+ *	Allocated within attach(9e) and freed within detach(9e).
+ *	Contains all 'per device' necessary handles, flags, locks etc.:
+ */
+struct s_AC  {
+	SK_GEINIT	GIni;		/* GE init struct */
+	SK_PNMI		Pnmi;		/* PNMI data struct */
+	SK_VPD		vpd;		/* vpd data struct */
+	SK_QUEUE	Event;		/* Event queue */
+	SK_HWT		Hwt;		/* Hardware Timer control struct */
+	SK_TIMCTRL	Tim;		/* Software Timer control struct */
+	SK_I2C		I2c;		/* I2C relevant data structure */
+	SK_ADDR		Addr;		/* for Address module */
+	SK_CSUM		Csum;		/* for checksum module */
+	SK_RLMT		Rlmt;		/* for rlmt module */
+#if 0
+	spinlock_t	SlowPathLock;	/* Normal IRQ lock */
+#endif
+	SK_PNMI_STRUCT_DATA PnmiStruct;	/* structure to get all Pnmi-Data */
+	int			RlmtMode;	/* link check mode to set */
+	int			RlmtNets;	/* Number of nets */
+
+	SK_IOC		IoBase;		/* register set of adapter */
+	int		BoardLevel;	/* level of active hw init (0-2) */
+	char		DeviceStr[80];	/* adapter string from vpd */
+	SK_U32		AllocFlag;	/* flag allocation of resources */
+#if 0
+	struct pci_dev	*PciDev;	/* for access to pci config space */
+	SK_U32		PciDevId;	/* pci device id */
+#else
+	int		PciDev;
+#endif
+	struct SK_NET_DEVICE	*dev[2];	/* pointer to device struct */
+	char		Name[30];	/* driver name */
+	struct SK_NET_DEVICE	*Next;		/* link all devices (for clearing) */
+	int		RxBufSize;	/* length of receive buffers */
+#if 0
+	struct net_device_stats stats;	/* linux 'netstat -i' statistics */
+#endif
+	int		Index;		/* internal board index number */
+
+	/* adapter RAM sizes for queues of active port */
+	int		RxQueueSize;	/* memory used for receive queue */
+	int		TxSQueueSize;	/* memory used for sync. tx queue */
+	int		TxAQueueSize;	/* memory used for async. tx queue */
+
+	int		PromiscCount;	/* promiscuous mode counter  */
+	int		AllMultiCount;  /* allmulticast mode counter */
+	int		MulticCount;	/* number of different MC    */
+					/*  addresses for this board */
+					/*  (may be more than HW can)*/
+
+	int		HWRevision;	/* Hardware revision */
+	int		ActivePort;	/* the active XMAC port */
+	int		MaxPorts;		/* number of activated ports */
+	int		TxDescrPerRing;	/* # of descriptors per tx ring */
+	int		RxDescrPerRing;	/* # of descriptors per rx ring */
+
+	caddr_t		pDescrMem;	/* Pointer to the descriptor area */
+	dma_addr_t	pDescrMemDMA;	/* PCI DMA address of area */
+
+	/* the port structures with descriptor rings */
+	TX_PORT		TxPort[SK_MAX_MACS][2];
+	RX_PORT		RxPort[SK_MAX_MACS];
+
+	unsigned int	CsOfs1;		/* for checksum calculation */
+	unsigned int	CsOfs2;		/* for checksum calculation */
+	SK_U32		CsOfs;		/* for checksum calculation */
+
+	SK_BOOL		CheckQueue;	/* check event queue soon */
+
+	/* Only for tests */
+	int		PortUp;
+	int		PortDown;
+
+};
+
+#endif /* __INC_SKDRV2ND_H */
diff --git a/drivers/net/sk98lin/h/skerror.h b/drivers/net/sk98lin/h/skerror.h
new file mode 100644
index 0000000..a454d9d
--- /dev/null
+++ b/drivers/net/sk98lin/h/skerror.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Name:	skerror.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 2002/04/25 11:05:10 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skerror.h,v $
+ *	Revision 1.5  2002/04/25 11:05:10  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.4  1999/11/22 13:51:59  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.3  1999/09/14 14:04:42  rwahl
+ *	Added error base SK_ERRBASE_PECP.
+ *	Changed error base for driver.
+ *
+ *	Revision 1.2  1998/08/11 11:15:41  gklug
+ *	chg: comments
+ *
+ *	Revision 1.1  1998/08/11 11:09:38  gklug
+ *	add: error bases
+ *	add: error Classes
+ *	first version
+ *
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKERROR_H_
+#define _INC_SKERROR_H_
+
+/*
+ * Define Error Classes
+ */
+#define	SK_ERRCL_OTHER		(0)		/* Other error */
+#define	SK_ERRCL_CONFIG		(1L<<0)	/* Configuration error */
+#define	SK_ERRCL_INIT		(1L<<1)	/* Initialization error */
+#define	SK_ERRCL_NORES		(1L<<2)	/* Out of Resources error */
+#define	SK_ERRCL_SW			(1L<<3)	/* Internal Software error */
+#define	SK_ERRCL_HW			(1L<<4)	/* Hardware Failure */
+#define	SK_ERRCL_COMM		(1L<<5)	/* Communication error */
+
+
+/*
+ * Define Error Code Bases
+ */
+#define	SK_ERRBASE_RLMT		 100	/* Base Error number for RLMT */
+#define	SK_ERRBASE_HWINIT	 200	/* Base Error number for HWInit */
+#define	SK_ERRBASE_VPD		 300	/* Base Error number for VPD */
+#define	SK_ERRBASE_PNMI		 400	/* Base Error number for PNMI */
+#define	SK_ERRBASE_CSUM		 500	/* Base Error number for Checksum */
+#define	SK_ERRBASE_SIRQ		 600	/* Base Error number for Special IRQ */
+#define	SK_ERRBASE_I2C		 700	/* Base Error number for I2C module */
+#define	SK_ERRBASE_QUEUE	 800	/* Base Error number for Scheduler */
+#define	SK_ERRBASE_ADDR		 900	/* Base Error number for Address module */
+#define SK_ERRBASE_PECP		1000    /* Base Error number for PECP */
+#define	SK_ERRBASE_DRV		1100	/* Base Error number for Driver */
+
+#endif	/* _INC_SKERROR_H_ */
diff --git a/drivers/net/sk98lin/h/skgedrv.h b/drivers/net/sk98lin/h/skgedrv.h
new file mode 100644
index 0000000..72ba9ce
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgedrv.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * Name:	skgedrv.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.6 $
+ * Date:	$Date: 2002/07/15 15:38:01 $
+ * Purpose:	Interface with the driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgedrv.h,v $
+ *	Revision 1.6  2002/07/15 15:38:01  rschmidt
+ *	Power Management support
+ *	Editorial changes
+ *
+ *	Revision 1.5  2002/04/25 11:05:47  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.4  1999/11/22 13:52:46  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.3  1998/12/01 13:31:39  cgoos
+ *	SWITCH INTERN Event added.
+ *
+ *	Revision 1.2  1998/11/25 08:28:38  gklug
+ *	rmv: PORT SWITCH Event
+ *
+ *	Revision 1.1  1998/09/29 06:14:07  gklug
+ *	add: driver events (initial version)
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEDRV_H_
+#define __INC_SKGEDRV_H_
+
+/* defines ********************************************************************/
+
+/*
+ * Define the driver events.
+ * Usually the events are defined by the destination module.
+ * In case of the driver we put the definition of the events here.
+ */
+#define SK_DRV_PORT_RESET		 1	/* The port needs to be reset */
+#define SK_DRV_NET_UP   		 2	/* The net is operational */
+#define SK_DRV_NET_DOWN			 3	/* The net is down */
+#define SK_DRV_SWITCH_SOFT		 4	/* Ports switch with both links connected */
+#define SK_DRV_SWITCH_HARD		 5	/* Port switch due to link failure */
+#define SK_DRV_RLMT_SEND		 6	/* Send a RLMT packet */
+#define SK_DRV_ADAP_FAIL		 7	/* The whole adapter fails */
+#define SK_DRV_PORT_FAIL		 8	/* One port fails */
+#define SK_DRV_SWITCH_INTERN	 9	/* Port switch by the driver itself */
+#define SK_DRV_POWER_DOWN		10	/* Power down mode */
+
+#endif	/* __INC_SKGEDRV_H_ */
diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h
new file mode 100644
index 0000000..2c98427
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehw.h
@@ -0,0 +1,2336 @@
+/******************************************************************************
+ *
+ * Name:	skgehw.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.49 $
+ * Date:	$Date: 2003/01/28 09:43:49 $
+ * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product Family
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ * $Log: skgehw.h,v $
+ * Revision 1.49  2003/01/28 09:43:49  rschmidt
+ * Added defines for PCI-Spec. 2.3 IRQ
+ * Added defines for CLK_RUN (YUKON-Lite)
+ * Editorial changes
+ *
+ * Revision 1.48  2002/12/05 10:25:11  rschmidt
+ * Added defines for Half Duplex Burst Mode On/Off
+ * Added defines for Rx GMAC FIFO Flush feature
+ * Editorial changes
+ *
+ * Revision 1.47  2002/11/12 17:01:31  rschmidt
+ * Added defines for WOL_CTL_DEFAULT
+ * Editorial changes
+ *
+ * Revision 1.46  2002/10/14 14:47:57  rschmidt
+ * Corrected bit mask for HW self test results
+ * Added defines for WOL Registers
+ * Editorial changes
+ *
+ * Revision 1.45  2002/10/11 09:25:22  mkarl
+ * Added bit mask for HW self test results.
+ *
+ * Revision 1.44  2002/08/16 14:44:36  rschmidt
+ * Added define GPC_HWCFG_GMII_FIB for YUKON Fiber
+ *
+ * Revision 1.43  2002/08/12 13:31:50  rschmidt
+ * Corrected macros for GMAC Address Registers: GM_INADDR(),
+ * GM_OUTADDR(), GM_INHASH, GM_OUTHASH.
+ * Editorial changes
+ *
+ * Revision 1.42  2002/08/08 15:37:56  rschmidt
+ * Added defines for Power Management Capabilities
+ * Editorial changes
+ *
+ * Revision 1.41  2002/07/23 16:02:25  rschmidt
+ * Added macro WOL_REG() to access WOL reg. (HW-Bug in YUKON 1st rev.)
+ *
+ * Revision 1.40  2002/07/15 15:41:37  rschmidt
+ * Added new defines for Power Management Cap. & Control
+ * Editorial changes
+ *
+ * Revision 1.39  2002/06/10 09:37:07  rschmidt
+ * Added macros for the ADDR-Modul
+ *
+ * Revision 1.38  2002/06/05 08:15:19  rschmidt
+ * Added defines for WOL Registers
+ * Editorial changes
+ *
+ * Revision 1.37  2002/04/25 11:39:23  rschmidt
+ * Added new defines for PCI Our Register 1
+ * Added new registers and defines for YUKON (Rx FIFO, Tx FIFO,
+ * Time Stamp Timer, GMAC Control, GPHY Control,Link Control,
+ * GMAC IRQ Source and Mask, Wake-up Frame Pattern Match);
+ * Added new defines for Control/Status (VAUX available)
+ * Added Chip ID for YUKON
+ * Added define for descriptors with UDP ext. for YUKON
+ * Added macros to access the GMAC
+ * Added new Phy Type for Marvell 88E1011S (GPHY)
+ * Editorial changes
+ *
+ * Revision 1.36  2000/11/09 12:32:49  rassmann
+ * Renamed variables.
+ *
+ * Revision 1.35  2000/05/19 10:17:13  cgoos
+ * Added inactivity check in PHY_READ (in DEBUG mode only).
+ *
+ * Revision 1.34  1999/11/22 13:53:40  cgoos
+ * Changed license header to GPL.
+ *
+ * Revision 1.33  1999/08/27 11:17:10  malthoff
+ * It's more savely to put brackets around macro parameters.
+ * Brackets added for PHY_READ and PHY_WRITE.
+ *
+ * Revision 1.32  1999/05/19 07:31:01  cgoos
+ * Changes for 1000Base-T.
+ * Added HWAC_LINK_LED macro.
+ *
+ * Revision 1.31  1999/03/12 13:27:40  malthoff
+ * Remove __STDC__.
+ *
+ * Revision 1.30  1999/02/09 09:28:20  malthoff
+ * Add PCI_ERRBITS.
+ *
+ * Revision 1.29  1999/01/26 08:55:48  malthoff
+ * Bugfix: The 16 bit field relations inside the descriptor are
+ * 	endianess dependend if the descriptor reversal feature
+ * 	(PCI_REV_DESC bit in PCI_OUR_REG_2) is enabled.
+ * 	Drivers which use this feature has to set the define
+ * 	SK_USE_REV_DESC.
+ *
+ * Revision 1.28  1998/12/10 11:10:22  malthoff
+ * bug fix: IS_IRQ_STAT and IS_IRQ_MST_ERR has been twisted.
+ *
+ * Revision 1.27  1998/11/13 14:19:21  malthoff
+ * Bug Fix: The bit definition of B3_PA_CTRL has completely
+ * changed from HW Spec v1.3 to v1.5.
+ *
+ * Revision 1.26  1998/11/04 08:31:48  cgoos
+ * Fixed byte ordering in XM_OUTADDR/XM_OUTHASH macros.
+ *
+ * Revision 1.25  1998/11/04 07:16:25  cgoos
+ * Changed byte ordering in XM_INADDR/XM_INHASH again.
+ *
+ * Revision 1.24  1998/11/02 11:08:43  malthoff
+ * RxCtrl and TxCtrl must be volatile.
+ *
+ * Revision 1.23  1998/10/28 13:50:45  malthoff
+ * Fix: Endian support missing in XM_IN/OUT-ADDR/HASH macros.
+ *
+ * Revision 1.22  1998/10/26 08:01:36  malthoff
+ * RX_MFF_CTRL1 is split up into RX_MFF_CTRL1,
+ * RX_MFF_STAT_TO, and RX_MFF_TIST_TO.
+ * TX_MFF_CTRL1 is split up TX_MFF_CTRL1 and TX_MFF_WAF.
+ *
+ * Revision 1.21  1998/10/20 07:43:10  malthoff
+ * Fix: XM_IN/OUT/ADDR/HASH macros:
+ * The pointer must be casted.
+ *
+ * Revision 1.20  1998/10/19 15:53:59  malthoff
+ * Remove ML proto definitions.
+ *
+ * Revision 1.19  1998/10/16 14:40:17  gklug
+ * fix: typo B0_XM_IMSK regs
+ *
+ * Revision 1.18  1998/10/16 09:46:54  malthoff
+ * Remove temp defines for ML diag prototype.
+ * Fix register definition for B0_XM1_PHY_DATA, B0_XM1_PHY_DATA
+ * B0_XM2_PHY_DATA, B0_XM2_PHY_ADDR, B0_XA1_CSR, B0_XS1_CSR,
+ * B0_XS2_CSR, and B0_XA2_CSR.
+ *
+ * Revision 1.17  1998/10/14 06:03:14  cgoos
+ * Changed shifted constant to ULONG.
+ *
+ * Revision 1.16  1998/10/09 07:05:41  malthoff
+ * Rename ALL_PA_ENA_TO to PA_ENA_TO_ALL.
+ *
+ * Revision 1.15  1998/10/05 07:54:23  malthoff
+ * Split up RB_CTRL and it's bit definition into
+ * RB_CTRL, RB_TST1, and RB_TST2.
+ * Rename RB_RX_HTPP to RB_RX_LTPP.
+ * Add ALL_PA_ENA_TO. Modify F_WATER_MARK
+ * according to HW Spec. v1.5.
+ * Add MFF_TX_CTRL_DEF.
+ *
+ * Revision 1.14  1998/09/28 13:31:16  malthoff
+ * bug fix: B2_MAC_3 is 0x110 not 0x114
+ *
+ * Revision 1.13  1998/09/24 14:42:56  malthoff
+ * Split the RX_MFF_TST into RX_MFF_CTRL2,
+ * RX_MFF_TST1, and RX_MFF_TST2.
+ * Rename RX_MFF_CTRL to RX_MFF_CTRL1.
+ * Add BMU bit CSR_SV_IDLE.
+ * Add macros PHY_READ() and PHY_WRITE().
+ * Rename macro SK_ADDR() to SK_HW_ADDR()
+ * because of conflicts with the Address Module.
+ *
+ * Revision 1.12  1998/09/16 07:25:33  malthoff
+ * Change the parameter order in the XM_INxx and XM_OUTxx macros,
+ * to have the IoC as first parameter.
+ *
+ * Revision 1.11  1998/09/03 09:58:41  malthoff
+ * Rework the XM_xxx macros. Use {} instead of () to
+ * be compatible with SK_xxx macros which are defined
+ * with {}.
+ *
+ * Revision 1.10  1998/09/02 11:16:39  malthoff
+ * Temporary modify B2_I2C_SW to make tests with
+ * the GE/ML prototype.
+ *
+ * Revision 1.9  1998/08/19 09:11:49  gklug
+ * fix: struct are removed from c-source (see CCC)
+ * add: typedefs for all structs
+ *
+ * Revision 1.8  1998/08/18 08:27:27  malthoff
+ * Add some temporary workarounds to test GE
+ * sources with the ML.
+ *
+ * Revision 1.7  1998/07/03 14:42:26  malthoff
+ * bug fix: Correct macro XMA().
+ * Add temporary workaround to access the PCI config space over I/O
+ *
+ * Revision 1.6  1998/06/23 11:30:36  malthoff
+ * Remove ';' with ',' in macors.
+ *
+ * Revision 1.5  1998/06/22 14:20:57  malthoff
+ * Add macro SK_ADDR(Base,Addr).
+ *
+ * Revision 1.4  1998/06/19 13:35:43  malthoff
+ * change 'pGec' with 'pAC'
+ *
+ * Revision 1.3  1998/06/17 14:58:16  cvs
+ * Lost keywords reinserted.
+ *
+ * Revision 1.1  1998/06/17 14:16:36  cvs
+ * created
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEHW_H
+#define __INC_SKGEHW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define BIT_31		(1UL << 31)
+#define BIT_30		(1L << 30)
+#define BIT_29		(1L << 29)
+#define BIT_28		(1L << 28)
+#define BIT_27		(1L << 27)
+#define BIT_26		(1L << 26)
+#define BIT_25		(1L << 25)
+#define BIT_24		(1L << 24)
+#define BIT_23		(1L << 23)
+#define BIT_22		(1L << 22)
+#define BIT_21		(1L << 21)
+#define BIT_20		(1L << 20)
+#define BIT_19		(1L << 19)
+#define BIT_18		(1L << 18)
+#define BIT_17		(1L << 17)
+#define BIT_16		(1L << 16)
+#define BIT_15		(1L << 15)
+#define BIT_14		(1L << 14)
+#define BIT_13		(1L << 13)
+#define BIT_12		(1L << 12)
+#define BIT_11		(1L << 11)
+#define BIT_10		(1L << 10)
+#define BIT_9		(1L << 9)
+#define BIT_8		(1L << 8)
+#define BIT_7		(1L << 7)
+#define BIT_6		(1L << 6)
+#define BIT_5		(1L << 5)
+#define BIT_4		(1L << 4)
+#define BIT_3		(1L << 3)
+#define BIT_2		(1L << 2)
+#define BIT_1		(1L << 1)
+#define BIT_0		1L
+
+#define BIT_15S		(1U << 15)
+#define BIT_14S		(1 << 14)
+#define BIT_13S		(1 << 13)
+#define BIT_12S		(1 << 12)
+#define BIT_11S		(1 << 11)
+#define BIT_10S		(1 << 10)
+#define BIT_9S		(1 << 9)
+#define BIT_8S		(1 << 8)
+#define BIT_7S 		(1 << 7)
+#define BIT_6S		(1 << 6)
+#define BIT_5S		(1 << 5)
+#define BIT_4S		(1 << 4)
+#define BIT_3S		(1 << 3)
+#define BIT_2S		(1 << 2)
+#define BIT_1S		(1 << 1)
+#define BIT_0S		1
+
+#define SHIFT31(x)	((x) << 31)
+#define SHIFT30(x)	((x) << 30)
+#define SHIFT29(x)	((x) << 29)
+#define SHIFT28(x)	((x) << 28)
+#define SHIFT27(x)	((x) << 27)
+#define SHIFT26(x)	((x) << 26)
+#define SHIFT25(x)	((x) << 25)
+#define SHIFT24(x)	((x) << 24)
+#define SHIFT23(x)	((x) << 23)
+#define SHIFT22(x)	((x) << 22)
+#define SHIFT21(x)	((x) << 21)
+#define SHIFT20(x)	((x) << 20)
+#define SHIFT19(x)	((x) << 19)
+#define SHIFT18(x)	((x) << 18)
+#define SHIFT17(x)	((x) << 17)
+#define SHIFT16(x)	((x) << 16)
+#define SHIFT15(x)	((x) << 15)
+#define SHIFT14(x)	((x) << 14)
+#define SHIFT13(x)	((x) << 13)
+#define SHIFT12(x)	((x) << 12)
+#define SHIFT11(x)	((x) << 11)
+#define SHIFT10(x)	((x) << 10)
+#define SHIFT9(x)	((x) << 9)
+#define SHIFT8(x)	((x) << 8)
+#define SHIFT7(x)	((x) << 7)
+#define SHIFT6(x)	((x) << 6)
+#define SHIFT5(x)	((x) << 5)
+#define SHIFT4(x)	((x) << 4)
+#define SHIFT3(x)	((x) << 3)
+#define SHIFT2(x)	((x) << 2)
+#define SHIFT1(x)	((x) << 1)
+#define SHIFT0(x)	((x) << 0)
+
+/*
+ * Configuration Space header
+ * Since this module is used for different OS', those may be
+ * duplicate on some of them (e.g. Linux). But to keep the
+ * common source, we have to live with this...
+ */
+#define PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define PCI_COMMAND		0x04	/* 16 bit	Command */
+#define PCI_STATUS		0x06	/* 16 bit	Status */
+#define PCI_REV_ID		0x08	/*  8 bit	Revision ID */
+#if 0
+#define PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#endif
+#define PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define PCI_LAT_TIM		0x0d	/*  8 bit	Latency Timer */
+#define PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define PCI_BIST		0x0f	/*  8 bit	Built-in selftest */
+#define PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+	/* Byte 0x18..0x2b:	reserved */
+#define PCI_SUB_VID		0x2c	/* 16 bit	Subsystem Vendor ID */
+#define PCI_SUB_ID		0x2e	/* 16 bit	Subsystem ID */
+#define PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
+#define PCI_CAP_PTR		0x34	/*  8 bit 	Capabilities Ptr */
+	/* Byte 35..3b:	reserved */
+#define PCI_IRQ_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define PCI_IRQ_PIN		0x3d	/*  8 bit	Interrupt Pin */
+#define PCI_MIN_GNT		0x3e	/*  8 bit	Min_Gnt */
+#define PCI_MAX_LAT		0x3f	/*  8 bit	Max_Lat */
+	/* Device Dependent Region */
+#define PCI_OUR_REG_1	0x40	/* 32 bit 	Our Register 1 */
+#define PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
+	/* Power Management Region */
+#define PCI_PM_CAP_ID	0x48	/*  8 bit 	Power Management Cap. ID */
+#define PCI_PM_NITEM	0x49	/*  8 bit 	Next Item Ptr */
+#define PCI_PM_CAP_REG	0x4a	/* 16 bit 	Power Management Capabilities */
+#define PCI_PM_CTL_STS	0x4c	/* 16 bit 	Power Manag. Control/Status */
+	/* Byte 0x4e:	reserved */
+#define PCI_PM_DAT_REG	0x4f	/*  8 bit 	Power Manag. Data Register */
+	/* VPD Region */
+#define PCI_VPD_CAP_ID	0x50	/*  8 bit 	VPD Cap. ID */
+#define PCI_VPD_NITEM	0x51	/*  8 bit 	Next Item Ptr */
+#define PCI_VPD_ADR_REG	0x52	/* 16 bit 	VPD Address Register */
+#define PCI_VPD_DAT_REG	0x54	/* 32 bit 	VPD Data Register */
+	/* Byte 0x58..0xff:	reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *	 I2C bus.
+ */
+#define I2C_ADDR_VPD	0xA0	/* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*	PCI_COMMAND	16 bit	Command */
+								/* Bit 15..11:	reserved */
+#define PCI_INT_DIS		BIT_10S		/* Interrupt INTx# disable (PCI 2.3) */
+#define PCI_FBTEN		BIT_9S		/* Fast Back-To-Back enable */
+#define PCI_SERREN		BIT_8S		/* SERR enable */
+#define PCI_ADSTEP		BIT_7S		/* Address Stepping */
+#define PCI_PERREN		BIT_6S		/* Parity Report Response enable */
+#define PCI_VGA_SNOOP	BIT_5S		/* VGA palette snoop */
+#define PCI_MWIEN		BIT_4S		/* Memory write an inv cycl ena */
+#define PCI_SCYCEN		BIT_3S		/* Special Cycle enable */
+#define PCI_BMEN		BIT_2S		/* Bus Master enable */
+#define PCI_MEMEN		BIT_1S		/* Memory Space Access enable */
+#define PCI_IOEN		BIT_0S		/* I/O Space Access enable */
+
+#define PCI_COMMAND_VAL	(PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\
+						 PCI_BMEN | PCI_MEMEN | PCI_IOEN)
+
+/*	PCI_STATUS	16 bit	Status */
+#define PCI_PERR		BIT_15S		/* Parity Error */
+#define PCI_SERR		BIT_14S		/* Signaled SERR */
+#define PCI_RMABORT		BIT_13S		/* Received Master Abort */
+#define PCI_RTABORT		BIT_12S		/* Received Target Abort */
+								/* Bit 11:	reserved */
+#define PCI_DEVSEL		(3<<9)		/* Bit 10.. 9:	DEVSEL Timing */
+#define PCI_DEV_FAST	(0<<9)		/*		fast */
+#define PCI_DEV_MEDIUM	(1<<9)		/*		medium */
+#define PCI_DEV_SLOW	(2<<9)		/*		slow */
+#define PCI_DATAPERR	BIT_8S		/* DATA Parity error detected */
+#define PCI_FB2BCAP		BIT_7S		/* Fast Back-to-Back Capability */
+#define PCI_UDF			BIT_6S		/* User Defined Features */
+#define PCI_66MHZCAP	BIT_5S		/* 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP		BIT_4S		/* New cap. list implemented */
+#define PCI_INT_STAT	BIT_3S		/* Interrupt INTx# Status (PCI 2.3) */
+								/* Bit  2.. 0:	reserved */
+
+#define PCI_ERRBITS	(PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
+			PCI_DATAPERR)
+
+/*	PCI_CLASS_CODE	24 bit	Class Code */
+/*	Byte 2:		Base Class		(02) */
+/*	Byte 1:		SubClass		(00) */
+/*	Byte 0:		Programming Interface	(00) */
+
+/*	PCI_CACHE_LSZ	8 bit	Cache Line Size */
+/*	Possible values: 0,2,4,8,16,32,64,128	*/
+
+/*	PCI_HEADER_T	8 bit	Header Type */
+#define PCI_HD_MF_DEV	BIT_7S	/* 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE		0x7f	/* Bit 6..0:	Header Layout 0= normal */
+
+/*	PCI_BIST	8 bit	Built-in selftest */
+/*	Built-in Self test not supported (optional) */
+
+/*	PCI_BASE_1ST	32 bit	1st Base address */
+#define PCI_MEMSIZE		0x4000L		/* use 16 kB Memory Base */
+#define PCI_MEMBASE_MSK 0xffffc000L	/* Bit 31..14:	Memory Base Address */
+#define PCI_MEMSIZE_MSK 0x00003ff0L	/* Bit 13.. 4:	Memory Size Req. */
+#define PCI_PREFEN		BIT_3		/* Prefetchable */
+#define PCI_MEM_TYP		(3L<<2)		/* Bit	2.. 1:	Memory Type */
+#define PCI_MEM32BIT	(0L<<1)		/* Base addr anywhere in 32 Bit range */
+#define PCI_MEM1M		(1L<<1)		/* Base addr below 1 MegaByte */
+#define PCI_MEM64BIT	(2L<<1)		/* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE	BIT_0		/* Memory Space Indic. */
+
+/*	PCI_BASE_2ND	32 bit	2nd Base address */
+#define PCI_IOBASE		0xffffff00L	/* Bit 31.. 8:	I/O Base address */
+#define PCI_IOSIZE		0x000000fcL	/* Bit	7.. 2:	I/O Size Requirements */
+									/* Bit	1:	reserved */
+#define PCI_IOSPACE		BIT_0		/* I/O Space Indicator */
+
+/*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
+#define PCI_ROMBASE		0xfffe0000L	/* Bit 31..17:	ROM BASE address (1st)*/
+#define PCI_ROMBASZ		(0x1cL<<14)	/* Bit 16..14:	Treat as BASE or SIZE */
+#define PCI_ROMSIZE		(0x38L<<11)	/* Bit 13..11:	ROM Size Requirements */
+									/* Bit 10.. 1:	reserved */
+#define PCI_ROMEN		BIT_0		/* Address Decode enable */
+
+/* Device Dependent Region */
+/*	PCI_OUR_REG_1		32 bit	Our Register 1 */
+									/* Bit 31..29:	reserved */
+#define PCI_PHY_COMA	BIT_28		/* Set PHY to Coma Mode */
+#define PCI_EN_CAL		BIT_27		/* Enable  PCI buffer strength calibr. */
+#define PCI_DIS_CAL		BIT_26		/* Disable PCI buffer strength calibr. */
+#define PCI_VIO			BIT_25		/* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */
+#define PCI_DIS_BOOT	BIT_24		/* Disable BOOT via ROM */
+#define PCI_EN_IO		BIT_23		/* Mapping to I/O space */
+#define PCI_EN_FPROM	BIT_22		/* Enable FLASH mapping to memory */
+									/*		1 = Map Flash to memory */
+									/*		0 = Disable addr. dec */
+#define PCI_PAGESIZE	(3L<<20)	/* Bit 21..20:	FLASH Page Size	*/
+#define PCI_PAGE_16		(0L<<20)	/*		16 k pages	*/
+#define PCI_PAGE_32K	(1L<<20)	/*		32 k pages	*/
+#define PCI_PAGE_64K	(2L<<20)	/*		64 k pages	*/
+#define PCI_PAGE_128K	(3L<<20)	/*		128 k pages	*/
+									/* Bit 19:	reserved	*/
+#define PCI_PAGEREG		(7L<<16)	/* Bit 18..16:	Page Register	*/
+#define PCI_NOTAR		BIT_15		/* No turnaround cycle */
+#define PCI_FORCE_BE	BIT_14		/* Assert all BEs on MR */
+#define PCI_DIS_MRL		BIT_13		/* Disable Mem Read Line */
+#define PCI_DIS_MRM		BIT_12		/* Disable Mem Read Multiple */
+#define PCI_DIS_MWI		BIT_11		/* Disable Mem Write & Invalidate */
+#define PCI_DISC_CLS	BIT_10		/* Disc: cacheLsz bound */
+#define PCI_BURST_DIS	BIT_9		/* Burst Disable */
+#define PCI_DIS_PCI_CLK	BIT_8		/* Disable PCI clock driving */
+#define PCI_SKEW_DAS	(0xfL<<4)	/* Bit	7.. 4:	Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE	0xfL		/* Bit	3.. 0:	Skew Ctrl, Base	*/
+
+
+/*	PCI_OUR_REG_2		32 bit	Our Register 2 */
+#define PCI_VPD_WR_THR	(0xffL<<24)	/* Bit 31..24:	VPD Write Threshold */
+#define PCI_DEV_SEL		(0x7fL<<17)	/* Bit 23..17:	EEPROM Device Select */
+#define PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 16..14:	VPD ROM Size	*/
+									/* Bit 13..12:	reserved	*/
+#define PCI_PATCH_DIR	(0xfL<<8)	/* Bit 11.. 8:	Ext Patches dir 3..0 */
+#define PCI_PATCH_DIR_3	BIT_11
+#define PCI_PATCH_DIR_2	BIT_10
+#define PCI_PATCH_DIR_1	BIT_9
+#define PCI_PATCH_DIR_0	BIT_8
+#define PCI_EXT_PATCHS	(0xfL<<4)	/* Bit	7.. 4:	Extended Patches 3..0 */
+#define PCI_EXT_PATCH_3	BIT_7
+#define PCI_EXT_PATCH_2	BIT_6
+#define PCI_EXT_PATCH_1	BIT_5
+#define PCI_EXT_PATCH_0	BIT_4
+#define PCI_EN_DUMMY_RD	BIT_3		/* Enable Dummy Read */
+#define PCI_REV_DESC	BIT_2		/* Reverse Desc. Bytes */
+									/* Bit	1:	reserved */
+#define PCI_USEDATA64	BIT_0		/* Use 64Bit Data bus ext */
+
+
+/* Power Management Region */
+/*	PCI_PM_CAP_REG		16 bit	Power Management Capabilities */
+#define PCI_PME_SUP_MSK	(0x1f<<11)	/* Bit 15..11:	PM Event Support Mask */
+#define PCI_PME_D3C_SUP	BIT_15S		/* PME from D3cold Support (if Vaux) */
+#define PCI_PME_D3H_SUP	BIT_14S		/* PME from D3hot Support */
+#define PCI_PME_D2_SUP	BIT_13S		/* PME from D2 Support */
+#define PCI_PME_D1_SUP	BIT_12S		/* PME from D1 Support */
+#define PCI_PME_D0_SUP	BIT_11S		/* PME from D0 Support */
+#define PCI_PM_D2_SUP	BIT_10S		/* D2 Support in 33 MHz mode */
+#define PCI_PM_D1_SUP	BIT_9S		/* D1 Support */
+									/* Bit	8.. 6:	reserved */
+#define PCI_PM_DSI		BIT_5S		/* Device Specific Initialization */
+#define PCI_PM_APS		BIT_4S		/* Auxialiary Power Source */
+#define PCI_PME_CLOCK	BIT_3S		/* PM Event Clock */
+#define PCI_PM_VER_MSK		7		/* Bit	2.. 0:	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit	Power Management Control/Status */
+#define PCI_PME_STATUS	BIT_15S		/* PME Status (YUKON only) */
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 14..13:	Data Reg. scaling factor */
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit 12.. 9:	PM data selector field */
+#define PCI_PME_EN		BIT_8S		/* Enable PME# generation (YUKON only) */
+									/* Bit	7.. 2:	reserved */
+#define PCI_PM_STATE_MSK	3		/* Bit	1.. 0:	Power Management State */
+
+#define PCI_PM_STATE_D0		0		/* D0:	Operational (default) */
+#define PCI_PM_STATE_D1		1		/* D1:	(YUKON only) */
+#define PCI_PM_STATE_D2		2		/* D2:	(YUKON only) */
+#define PCI_PM_STATE_D3 	3		/* D3:	HOT, Power Down and Reset */
+
+/* VPD Region */
+/*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
+#define PCI_VPD_FLAG	BIT_15S		/* starts VPD rd/wr cycle */
+#define PCI_VPD_ADR_MSK	0x7fffL		/* Bit 14.. 0:	VPD address mask */
+
+/*	Control Register File (Address Map) */
+
+/*
+ *	Bank 0
+ */
+#define B0_RAP			0x0000	/*  8 bit	Register Address Port */
+	/* 0x0001 - 0x0003:	reserved */
+#define B0_CTST			0x0004	/* 16 bit	Control/Status register */
+#define B0_LED			0x0006	/*  8 Bit	LED register */
+#define B0_POWER_CTRL	0x0007	/*  8 Bit	Power Control reg (YUKON only) */
+#define B0_ISRC			0x0008	/* 32 bit	Interrupt Source Register */
+#define B0_IMSK			0x000c	/* 32 bit	Interrupt Mask Register */
+#define B0_HWE_ISRC		0x0010	/* 32 bit	HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK		0x0014	/* 32 bit	HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC		0x0018	/* 32 bit	Special Interrupt Source Reg */
+	/* 0x001c:		reserved */
+
+/* B0 XMAC 1 registers (GENESIS only) */
+#define B0_XM1_IMSK		0x0020	/* 16 bit r/w	XMAC 1 Interrupt Mask Register*/
+	/* 0x0022 - 0x0027:	reserved */
+#define B0_XM1_ISRC		0x0028	/* 16 bit ro	XMAC 1 Interrupt Status Reg */
+	/* 0x002a - 0x002f:	reserved */
+#define B0_XM1_PHY_ADDR 0x0030	/* 16 bit r/w	XMAC 1 PHY Address Register */
+	/* 0x0032 - 0x0033:	reserved */
+#define B0_XM1_PHY_DATA 0x0034	/* 16 bit r/w	XMAC 1 PHY Data Register */
+	/* 0x0036 - 0x003f:	reserved */
+
+/* B0 XMAC 2 registers (GENESIS only) */
+#define B0_XM2_IMSK		0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
+	/* 0x0042 - 0x0047:	reserved */
+#define B0_XM2_ISRC		0x0048	/* 16 bit ro	XMAC 2 Interrupt Status Reg */
+	/* 0x004a - 0x004f:	reserved */
+#define B0_XM2_PHY_ADDR 0x0050	/* 16 bit r/w	XMAC 2 PHY Address Register */
+	/* 0x0052 - 0x0053:	reserved */
+#define B0_XM2_PHY_DATA 0x0054	/* 16 bit r/w	XMAC 2 PHY Data Register */
+	/* 0x0056 - 0x005f:	reserved */
+
+/* BMU Control Status Registers */
+#define B0_R1_CSR		0x0060	/* 32 bit	BMU Ctrl/Stat Rx Queue 1 */
+#define B0_R2_CSR		0x0064	/* 32 bit	BMU Ctrl/Stat Rx Queue 2 */
+#define B0_XS1_CSR		0x0068	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+#define B0_XA1_CSR		0x006c	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 1*/
+#define B0_XS2_CSR		0x0070	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+#define B0_XA2_CSR		0x0074	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 2*/
+	/* 0x0078 - 0x007f:	reserved */
+
+/*
+ *	Bank 1
+ *	- completely empty (this is the RAP Block window)
+ *	Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *	Bank 2
+ */
+/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
+#define B2_MAC_1		0x0100	/* NA reg	 MAC Address 1 */
+	/* 0x0106 - 0x0107:	reserved */
+#define B2_MAC_2		0x0108	/* NA reg	 MAC Address 2 */
+	/* 0x010e - 0x010f:	reserved */
+#define B2_MAC_3		0x0110	/* NA reg	 MAC Address 3 */
+	/* 0x0116 - 0x0117:	reserved */
+#define B2_CONN_TYP		0x0118	/*  8 bit	Connector type */
+#define B2_PMD_TYP		0x0119	/*  8 bit	PMD type */
+#define B2_MAC_CFG		0x011a	/*  8 bit	MAC Configuration / Chip Revision */
+#define B2_CHIP_ID		0x011b	/*  8 bit 	Chip Identification Number */
+	/* Eprom registers are currently of no use */
+#define B2_E_0			0x011c	/*  8 bit	EPROM Byte 0 (ext. SRAM size */
+#define B2_E_1			0x011d	/*  8 bit	EPROM Byte 1 (PHY type) */
+#define B2_E_2			0x011e	/*  8 bit	EPROM Byte 2 */
+#define B2_E_3			0x011f	/*  8 bit	EPROM Byte 3 */
+#define B2_FAR			0x0120	/* 32 bit	Flash-Prom Addr Reg/Cnt */
+#define B2_FDP			0x0124	/*  8 bit	Flash-Prom Data Port */
+	/* 0x0125 - 0x0127:	reserved */
+#define B2_LD_CRTL		0x0128	/*  8 bit	EPROM loader control register */
+#define B2_LD_TEST		0x0129	/*  8 bit	EPROM loader test register */
+	/* 0x012a - 0x012f:	reserved */
+#define B2_TI_INI		0x0130	/* 32 bit	Timer Init Value */
+#define B2_TI_VAL		0x0134	/* 32 bit	Timer Value */
+#define B2_TI_CRTL		0x0138	/*  8 bit	Timer Control */
+#define B2_TI_TEST		0x0139	/*  8 Bit	Timer Test */
+	/* 0x013a - 0x013f:	reserved */
+#define B2_IRQM_INI		0x0140	/* 32 bit	IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL		0x0144	/* 32 bit	IRQ Moderation Timer Value */
+#define B2_IRQM_CTRL	0x0148	/*  8 bit	IRQ Moderation Timer Control */
+#define B2_IRQM_TEST	0x0149	/*  8 bit	IRQ Moderation Timer Test */
+#define B2_IRQM_MSK 	0x014c	/* 32 bit	IRQ Moderation Mask */
+#define B2_IRQM_HWE_MSK 0x0150	/* 32 bit	IRQ Moderation HW Error Mask */
+	/* 0x0154 - 0x0157:	reserved */
+#define B2_TST_CTRL1	0x0158	/*  8 bit	Test Control Register 1 */
+#define B2_TST_CTRL2	0x0159	/*  8 bit	Test Control Register 2 */
+	/* 0x015a - 0x015b:	reserved */
+#define B2_GP_IO		0x015c	/* 32 bit	General Purpose I/O Register */
+#define B2_I2C_CTRL		0x0160	/* 32 bit	I2C HW Control Register */
+#define B2_I2C_DATA		0x0164	/* 32 bit	I2C HW Data Register */
+#define B2_I2C_IRQ		0x0168	/* 32 bit	I2C HW IRQ Register */
+#define B2_I2C_SW		0x016c	/* 32 bit	I2C SW Port Register */
+
+/* Blink Source Counter (GENESIS only) */
+#define B2_BSC_INI		0x0170	/* 32 bit	Blink Source Counter Init Val */
+#define B2_BSC_VAL		0x0174	/* 32 bit	Blink Source Counter Value */
+#define B2_BSC_CTRL		0x0178	/*  8 bit	Blink Source Counter Control */
+#define B2_BSC_STAT		0x0179	/*  8 bit	Blink Source Counter Status */
+#define B2_BSC_TST		0x017a	/* 16 bit	Blink Source Counter Test Reg */
+	/* 0x017c - 0x017f:	reserved */
+
+/*
+ *	Bank 3
+ */
+/* RAM Random Registers */
+#define B3_RAM_ADDR		0x0180	/* 32 bit	RAM Address, to read or write */
+#define B3_RAM_DATA_LO	0x0184	/* 32 bit	RAM Data Word (low dWord) */
+#define B3_RAM_DATA_HI	0x0188	/* 32 bit	RAM Data Word (high dWord) */
+	/* 0x018c - 0x018f:	reserved */
+
+/* RAM Interface Registers */
+/*
+ * The HW-Spec. calls this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transferred continuously.
+ */
+#define B3_RI_WTO_R1	0x0190	/*  8 bit	WR Timeout Queue R1		(TO0) */
+#define B3_RI_WTO_XA1	0x0191	/*  8 bit	WR Timeout Queue XA1	(TO1) */
+#define B3_RI_WTO_XS1	0x0192	/*  8 bit	WR Timeout Queue XS1	(TO2) */
+#define B3_RI_RTO_R1	0x0193	/*  8 bit	RD Timeout Queue R1		(TO3) */
+#define B3_RI_RTO_XA1	0x0194	/*  8 bit	RD Timeout Queue XA1	(TO4) */
+#define B3_RI_RTO_XS1	0x0195	/*  8 bit	RD Timeout Queue XS1	(TO5) */
+#define B3_RI_WTO_R2	0x0196	/*  8 bit	WR Timeout Queue R2		(TO6) */
+#define B3_RI_WTO_XA2	0x0197	/*  8 bit	WR Timeout Queue XA2	(TO7) */
+#define B3_RI_WTO_XS2	0x0198	/*  8 bit	WR Timeout Queue XS2	(TO8) */
+#define B3_RI_RTO_R2	0x0199	/*  8 bit	RD Timeout Queue R2		(TO9) */
+#define B3_RI_RTO_XA2	0x019a	/*  8 bit	RD Timeout Queue XA2	(TO10)*/
+#define B3_RI_RTO_XS2	0x019b	/*  8 bit	RD Timeout Queue XS2	(TO11)*/
+#define B3_RI_TO_VAL	0x019c	/*  8 bit	Current Timeout Count Val */
+	/* 0x019d - 0x019f:	reserved */
+#define B3_RI_CTRL		0x01a0	/* 16 bit	RAM Interface Control Register */
+#define B3_RI_TEST		0x01a2	/*  8 bit	RAM Interface Test Register */
+	/* 0x01a3 - 0x01af:	reserved */
+
+/* MAC Arbiter Registers (GENESIS only) */
+/* these are the no. of qWord transferred continuously and NOT real timeouts */
+#define B3_MA_TOINI_RX1	0x01b0	/*  8 bit	Timeout Init Val Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2	0x01b1	/*  8 bit	Timeout Init Val Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1	0x01b2	/*  8 bit	Timeout Init Val Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2	0x01b3	/*  8 bit	Timeout Init Val Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1	0x01b4	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2	0x01b5	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1	0x01b6	/*  8 bit	Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2	0x01b7	/*  8 bit	Timeout Value Tx Path MAC 2 */
+#define B3_MA_TO_CTRL	0x01b8	/* 16 bit	MAC Arbiter Timeout Ctrl Reg */
+#define B3_MA_TO_TEST	0x01ba	/* 16 bit	MAC Arbiter Timeout Test Reg */
+	/* 0x01bc - 0x01bf:	reserved */
+#define B3_MA_RCINI_RX1	0x01c0	/*  8 bit	Recovery Init Val Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2	0x01c1	/*  8 bit	Recovery Init Val Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1	0x01c2	/*  8 bit	Recovery Init Val Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2	0x01c3	/*  8 bit	Recovery Init Val Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1	0x01c4	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2	0x01c5	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1	0x01c6	/*  8 bit	Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2	0x01c7	/*  8 bit	Recovery Value Tx Path MAC 2 */
+#define B3_MA_RC_CTRL	0x01c8	/* 16 bit	MAC Arbiter Recovery Ctrl Reg */
+#define B3_MA_RC_TEST	0x01ca	/* 16 bit	MAC Arbiter Recovery Test Reg */
+	/* 0x01cc - 0x01cf:	reserved */
+
+/* Packet Arbiter Registers (GENESIS only) */
+/* these are real timeouts */
+#define B3_PA_TOINI_RX1	0x01d0	/* 16 bit	Timeout Init Val Rx Path MAC 1 */
+	/* 0x01d2 - 0x01d3:	reserved */
+#define B3_PA_TOINI_RX2	0x01d4	/* 16 bit	Timeout Init Val Rx Path MAC 2 */
+	/* 0x01d6 - 0x01d7:	reserved */
+#define B3_PA_TOINI_TX1	0x01d8	/* 16 bit	Timeout Init Val Tx Path MAC 1 */
+	/* 0x01da - 0x01db:	reserved */
+#define B3_PA_TOINI_TX2	0x01dc	/* 16 bit	Timeout Init Val Tx Path MAC 2 */
+	/* 0x01de - 0x01df:	reserved */
+#define B3_PA_TOVAL_RX1	0x01e0	/* 16 bit	Timeout Val Rx Path MAC 1 */
+	/* 0x01e2 - 0x01e3:	reserved */
+#define B3_PA_TOVAL_RX2	0x01e4	/* 16 bit	Timeout Val Rx Path MAC 2 */
+	/* 0x01e6 - 0x01e7:	reserved */
+#define B3_PA_TOVAL_TX1	0x01e8	/* 16 bit	Timeout Val Tx Path MAC 1 */
+	/* 0x01ea - 0x01eb:	reserved */
+#define B3_PA_TOVAL_TX2	0x01ec	/* 16 bit	Timeout Val Tx Path MAC 2 */
+	/* 0x01ee - 0x01ef:	reserved */
+#define B3_PA_CTRL	0x01f0	/* 16 bit	Packet Arbiter Ctrl Register */
+#define B3_PA_TEST	0x01f2	/* 16 bit	Packet Arbiter Test Register */
+	/* 0x01f4 - 0x01ff:	reserved */
+
+/*
+ *	Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+#define TXA_ITI_INI		0x0200	/* 32 bit	Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL		0x0204	/* 32 bit	Tx Arb Interval Timer Value */
+#define TXA_LIM_INI		0x0208	/* 32 bit	Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL		0x020c	/* 32 bit	Tx Arb Limit Counter Value */
+#define TXA_CTRL		0x0210	/*  8 bit	Tx Arbiter Control Register */
+#define TXA_TEST		0x0211	/*  8 bit	Tx Arbiter Test Register */
+#define TXA_STAT		0x0212	/*  8 bit	Tx Arbiter Status Register */
+	/* 0x0213 - 0x027f:	reserved */
+	/* 0x0280 - 0x0292:	MAC 2 */
+	/* 0x0213 - 0x027f:	reserved */
+
+/*
+ *	Bank 6
+ */
+/* External registers (GENESIS only) */
+#define B6_EXT_REG		0x0300
+
+/*
+ *	Bank 7
+ */
+/* This is a copy of the Configuration register file (lower half) */
+#define B7_CFG_SPC		0x0380
+
+/*
+ *	Bank 8 - 15
+ */
+/* Receive and Transmit Queue Registers, use Q_ADDR() to access */
+#define B8_Q_REGS		0x0400
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+#define Q_D		0x00	/* 8*32	bit	Current Descriptor */
+#define Q_DA_L	0x20	/* 32 bit	Current Descriptor Address Low dWord */
+#define Q_DA_H	0x24	/* 32 bit	Current Descriptor Address High dWord */
+#define Q_AC_L	0x28	/* 32 bit	Current Address Counter Low dWord */
+#define Q_AC_H	0x2c	/* 32 bit	Current Address Counter High dWord */
+#define Q_BC	0x30	/* 32 bit	Current Byte Counter */
+#define Q_CSR	0x34	/* 32 bit	BMU Control/Status Register */
+#define Q_F		0x38	/* 32 bit	Flag Register */
+#define Q_T1	0x3c	/* 32 bit	Test Register 1 */
+#define Q_T1_TR	0x3c	/*  8 bit	Test Register 1 Transfer SM */
+#define Q_T1_WR	0x3d	/*  8 bit	Test Register 1 Write Descriptor SM */
+#define Q_T1_RD	0x3e	/*  8 bit	Test Register 1 Read Descriptor SM */
+#define Q_T1_SV	0x3f	/*  8 bit	Test Register 1 Supervisor SM */
+#define Q_T2	0x40	/* 32 bit	Test Register 2	*/
+#define Q_T3	0x44	/* 32 bit	Test Register 3	*/
+	/* 0x48 - 0x7f:	reserved */
+
+/*
+ *	Bank 16 - 23
+ */
+/* RAM Buffer Registers */
+#define B16_RAM_REGS	0x0800
+
+/* RAM Buffer Register Offsets, use RB_ADDR() to access */
+#define RB_START		0x00	/* 32 bit	RAM Buffer Start Address */
+#define RB_END			0x04	/* 32 bit	RAM Buffer End Address */
+#define RB_WP			0x08	/* 32 bit	RAM Buffer Write Pointer */
+#define RB_RP			0x0c	/* 32 bit	RAM Buffer Read Pointer */
+#define RB_RX_UTPP		0x10	/* 32 bit	Rx Upper Threshold, Pause Pack */
+#define RB_RX_LTPP		0x14	/* 32 bit	Rx Lower Threshold, Pause Pack */
+#define RB_RX_UTHP		0x18	/* 32 bit	Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP		0x1c	/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+#define RB_PC			0x20	/* 32 bit	RAM Buffer Packet Counter */
+#define RB_LEV			0x24	/* 32 bit	RAM Buffer Level Register */
+#define RB_CTRL			0x28	/*  8 bit	RAM Buffer Control Register */
+#define RB_TST1			0x29	/*  8 bit	RAM Buffer Test Register 1 */
+#define RB_TST2			0x2A	/*  8 bit	RAM Buffer Test Register 2 */
+	/* 0x2c - 0x7f:	reserved */
+
+/*
+ *	Bank 24
+ */
+/*
+ * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only)
+ * use MR_ADDR() to access
+ */
+#define RX_MFF_EA		0x0c00	/* 32 bit	Receive MAC FIFO End Address */
+#define RX_MFF_WP		0x0c04	/* 32 bit 	Receive MAC FIFO Write Pointer */
+	/* 0x0c08 - 0x0c0b:	reserved */
+#define RX_MFF_RP		0x0c0c	/* 32 bit	Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC		0x0c10	/* 32 bit	Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV		0x0c14	/* 32 bit	Receive MAC FIFO Level */
+#define RX_MFF_CTRL1	0x0c18	/* 16 bit	Receive MAC FIFO Control Reg 1*/
+#define RX_MFF_STAT_TO	0x0c1a	/*  8 bit	Receive MAC Status Timeout */
+#define RX_MFF_TIST_TO	0x0c1b	/*  8 bit	Receive MAC Time Stamp Timeout */
+#define RX_MFF_CTRL2	0x0c1c	/*  8 bit	Receive MAC FIFO Control Reg 2*/
+#define RX_MFF_TST1		0x0c1d	/*  8 bit	Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2		0x0c1e	/*  8 bit	Receive MAC FIFO Test Reg 2 */
+	/* 0x0c1f:	reserved */
+#define RX_LED_INI		0x0c20	/* 32 bit	Receive LED Cnt Init Value */
+#define RX_LED_VAL		0x0c24	/* 32 bit	Receive LED Cnt Current Value */
+#define RX_LED_CTRL		0x0c28	/*  8 bit	Receive LED Cnt Control Reg */
+#define RX_LED_TST		0x0c29	/*  8 bit	Receive LED Cnt Test Register */
+	/* 0x0c2a - 0x0c2f:	reserved */
+#define LNK_SYNC_INI	0x0c30	/* 32 bit	Link Sync Cnt Init Value */
+#define LNK_SYNC_VAL	0x0c34	/* 32 bit	Link Sync Cnt Current Value */
+#define LNK_SYNC_CTRL	0x0c38	/*  8 bit	Link Sync Cnt Control Register */
+#define LNK_SYNC_TST	0x0c39	/*  8 bit	Link Sync Cnt Test Register */
+	/* 0x0c3a - 0x0c3b:	reserved */
+#define LNK_LED_REG		0x0c3c	/*  8 bit	Link LED Register */
+	/* 0x0c3d - 0x0c3f:	reserved */
+
+/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define RX_GMF_EA		0x0c40	/* 32 bit	Rx GMAC FIFO End Address */
+#define RX_GMF_AF_THR	0x0c44	/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+#define RX_GMF_CTRL_T	0x0c48	/* 32 bit	Rx GMAC FIFO Control/Test */
+#define RX_GMF_FL_MSK	0x0c4c	/* 32 bit	Rx GMAC FIFO Flush Mask */
+#define RX_GMF_FL_THR	0x0c50	/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	/* 0x0c54 - 0x0c5f:	reserved */
+#define RX_GMF_WP		0x0c60	/* 32 bit 	Rx GMAC FIFO Write Pointer */
+	/* 0x0c64 - 0x0c67:	reserved */
+#define RX_GMF_WLEV		0x0c68	/* 32 bit 	Rx GMAC FIFO Write Level */
+	/* 0x0c6c - 0x0c6f:	reserved */
+#define RX_GMF_RP		0x0c70	/* 32 bit 	Rx GMAC FIFO Read Pointer */
+	/* 0x0c74 - 0x0c77:	reserved */
+#define RX_GMF_RLEV		0x0c78	/* 32 bit 	Rx GMAC FIFO Read Level */
+	/* 0x0c7c - 0x0c7f:	reserved */
+
+/*
+ *	Bank 25
+ */
+	/* 0x0c80 - 0x0cbf:	MAC 2 */
+	/* 0x0cc0 - 0x0cff:	reserved */
+
+/*
+ *	Bank 26
+ */
+/*
+ * Transmit MAC FIFO and Transmit LED Registers (GENESIS only),
+ * use MR_ADDR() to access
+ */
+#define TX_MFF_EA		0x0d00	/* 32 bit	Transmit MAC FIFO End Address */
+#define TX_MFF_WP		0x0d04	/* 32 bit 	Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP		0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Ptr */
+#define TX_MFF_RP		0x0d0c	/* 32 bit	Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC		0x0d10	/* 32 bit	Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV		0x0d14	/* 32 bit	Transmit MAC FIFO Level */
+#define TX_MFF_CTRL1	0x0d18	/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
+#define TX_MFF_WAF		0x0d1a	/*  8 bit	Transmit MAC Wait after flush */
+	/* 0x0c1b:	reserved */
+#define TX_MFF_CTRL2	0x0d1c	/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
+#define TX_MFF_TST1		0x0d1d	/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2		0x0d1e	/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+	/* 0x0d1f:	reserved */
+#define TX_LED_INI		0x0d20	/* 32 bit	Transmit LED Cnt Init Value */
+#define TX_LED_VAL		0x0d24	/* 32 bit	Transmit LED Cnt Current Val */
+#define TX_LED_CTRL		0x0d28	/*  8 bit	Transmit LED Cnt Control Reg */
+#define TX_LED_TST		0x0d29	/*  8 bit	Transmit LED Cnt Test Reg */
+	/* 0x0d2a - 0x0d3f:	reserved */
+
+/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define TX_GMF_EA		0x0d40	/* 32 bit	Tx GMAC FIFO End Address */
+#define TX_GMF_AE_THR	0x0d44	/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+#define TX_GMF_CTRL_T	0x0d48	/* 32 bit	Tx GMAC FIFO Control/Test */
+	/* 0x0d4c - 0x0d5f:	reserved */
+#define TX_GMF_WP		0x0d60	/* 32 bit 	Tx GMAC FIFO Write Pointer */
+#define TX_GMF_WSP		0x0d64	/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+#define TX_GMF_WLEV		0x0d68	/* 32 bit 	Tx GMAC FIFO Write Level */
+	/* 0x0d6c - 0x0d6f:	reserved */
+#define TX_GMF_RP		0x0d70	/* 32 bit 	Tx GMAC FIFO Read Pointer */
+#define TX_GMF_RSTP		0x0d74	/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+#define TX_GMF_RLEV		0x0d78	/* 32 bit 	Tx GMAC FIFO Read Level */
+	/* 0x0d7c - 0x0d7f:	reserved */
+
+/*
+ *	Bank 27
+ */
+	/* 0x0d80 - 0x0dbf:	MAC 2 */
+	/* 0x0daa - 0x0dff:	reserved */
+
+/*
+ *	Bank 28
+ */
+/* Descriptor Poll Timer Registers */
+#define B28_DPT_INI		0x0e00	/* 24 bit	Descriptor Poll Timer Init Val */
+#define B28_DPT_VAL		0x0e04	/* 24 bit	Descriptor Poll Timer Curr Val */
+#define B28_DPT_CTRL	0x0e08	/*  8 bit	Descriptor Poll Timer Ctrl Reg */
+	/* 0x0e09:	reserved */
+#define B28_DPT_TST		0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg */
+	/* 0x0e0b:	reserved */
+
+/* Time Stamp Timer Registers (YUKON only) */
+	/* 0x0e10:	reserved */
+#define GMAC_TI_ST_VAL	0x0e14	/* 32 bit	Time Stamp Timer Curr Val */
+#define GMAC_TI_ST_CTRL	0x0e18	/*  8 bit	Time Stamp Timer Ctrl Reg */
+	/* 0x0e19:	reserved */
+#define GMAC_TI_ST_TST	0x0e1a	/*  8 bit	Time Stamp Timer Test Reg */
+	/* 0x0e1b - 0x0e7f:	reserved */
+
+/*
+ *	Bank 29
+ */
+	/* 0x0e80 - 0x0efc:	reserved */
+
+/*
+ *	Bank 30
+ */
+/* GMAC and GPHY Control Registers (YUKON only) */
+#define GMAC_CTRL		0x0f00	/* 32 bit	GMAC Control Reg */
+#define GPHY_CTRL		0x0f04	/* 32 bit	GPHY Control Reg */
+#define GMAC_IRQ_SRC	0x0f08	/*  8 bit	GMAC Interrupt Source Reg */
+	/* 0x0f09 - 0x0f0b:	reserved */
+#define GMAC_IRQ_MSK	0x0f0c	/*  8 bit	GMAC Interrupt Mask Reg */
+	/* 0x0f0d - 0x0f0f:	reserved */
+#define GMAC_LINK_CTRL	0x0f10	/* 16 bit	Link Control Reg */
+	/* 0x0f14 - 0x0f1f:	reserved */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+#define WOL_REG_OFFS	0x20	/* HW-Bug: Address is + 0x20 against spec. */
+
+#define WOL_CTRL_STAT	0x0f20	/* 16 bit	WOL Control/Status Reg */
+#define WOL_MATCH_CTL	0x0f22	/*  8 bit	WOL Match Control Reg */
+#define WOL_MATCH_RES	0x0f23	/*  8 bit	WOL Match Result Reg */
+#define WOL_MAC_ADDR_LO	0x0f24	/* 32 bit	WOL MAC Address Low */
+#define WOL_MAC_ADDR_HI	0x0f28	/* 16 bit	WOL MAC Address High */
+#define WOL_PATT_RPTR	0x0f2c	/*  8 bit	WOL Pattern Read Ptr */
+
+/* use this macro to access above registers */
+#define WOL_REG(Reg)	((Reg) + (pAC->GIni.GIWolOffs))
+
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+#define WOL_PATT_LEN_LO	0x0f30		/* 32 bit	WOL Pattern Length 3..0 */
+#define WOL_PATT_LEN_HI	0x0f34		/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+#define WOL_PATT_CNT_0	0x0f38		/* 32 bit	WOL Pattern Counter 3..0 */
+#define WOL_PATT_CNT_4	0x0f3c		/* 24 bit	WOL Pattern Counter 6..4 */
+	/* 0x0f40 - 0x0f7f:	reserved */
+
+/*
+ *	Bank 31
+ */
+/* 0x0f80 - 0x0fff:	reserved */
+
+/*
+ *	Bank 32	- 33
+ */
+#define WOL_PATT_RAM_1	0x1000	/*  WOL Pattern RAM Link 1 */
+
+/*
+ *	Bank 0x22 - 0x3f
+ */
+/* 0x1100 - 0x1fff:	reserved */
+
+/*
+ *	Bank 0x40 - 0x4f
+ */
+#define BASE_XMAC_1		0x2000	/* XMAC 1 registers */
+
+/*
+ *	Bank 0x50 - 0x5f
+ */
+
+#define BASE_GMAC_1		0x2800	/* GMAC 1 registers */
+
+/*
+ *	Bank 0x60 - 0x6f
+ */
+#define BASE_XMAC_2		0x3000	/* XMAC 2 registers */
+
+/*
+ *	Bank 0x70 - 0x7f
+ */
+#define BASE_GMAC_2		0x3800	/* GMAC 2 registers */
+
+/*
+ *	Control Register Bit Definitions:
+ */
+/*	B0_RAP		8 bit	Register Address Port */
+								/* Bit 7:	reserved */
+#define RAP_RAP			0x3f	/* Bit 6..0:	0 = block 0,..,6f = block 6f */
+
+/*	B0_CTST		16 bit	Control/Status register */
+								/* Bit 15..14:	reserved */
+#define CS_CLK_RUN_HOT	BIT_13S		/* CLK_RUN hot m. (YUKON-Lite only) */
+#define CS_CLK_RUN_RST	BIT_12S		/* CLK_RUN reset  (YUKON-Lite only) */
+#define CS_CLK_RUN_ENA	BIT_11S		/* CLK_RUN enable (YUKON-Lite only) */
+#define CS_VAUX_AVAIL	BIT_10S		/* VAUX available (YUKON only) */
+#define CS_BUS_CLOCK	BIT_9S		/* Bus Clock 0/1 = 33/66 MHz */
+#define CS_BUS_SLOT_SZ	BIT_8S		/* Slot Size 0/1 = 32/64 bit slot */
+#define CS_ST_SW_IRQ	BIT_7S		/* Set IRQ SW Request */
+#define CS_CL_SW_IRQ	BIT_6S		/* Clear IRQ SW Request */
+#define CS_STOP_DONE	BIT_5S		/* Stop Master is finished */
+#define CS_STOP_MAST	BIT_4S		/* Command Bit to stop the master */
+#define CS_MRST_CLR		BIT_3S		/* Clear Master reset	*/
+#define CS_MRST_SET		BIT_2S		/* Set Master reset	*/
+#define CS_RST_CLR		BIT_1S		/* Clear Software reset	*/
+#define CS_RST_SET		BIT_0S		/* Set   Software reset	*/
+
+/*	B0_LED		 8 Bit	LED register */
+								/* Bit  7.. 2:	reserved */
+#define LED_STAT_ON		BIT_1S		/* Status LED on	*/
+#define LED_STAT_OFF	BIT_0S		/* Status LED off	*/
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+#define PC_VAUX_ENA		BIT_7		/* Switch VAUX Enable  */
+#define PC_VAUX_DIS		BIT_6       /* Switch VAUX Disable */
+#define PC_VCC_ENA		BIT_5       /* Switch VCC Enable  */
+#define PC_VCC_DIS		BIT_4       /* Switch VCC Disable */
+#define PC_VAUX_ON		BIT_3       /* Switch VAUX On  */
+#define PC_VAUX_OFF		BIT_2       /* Switch VAUX Off */
+#define PC_VCC_ON		BIT_1       /* Switch VCC On  */
+#define PC_VCC_OFF		BIT_0       /* Switch VCC Off */
+
+/*	B0_ISRC		32 bit	Interrupt Source Register */
+/*	B0_IMSK		32 bit	Interrupt Mask Register */
+/*	B0_SP_ISRC	32 bit	Special Interrupt Source Reg */
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+#define IS_ALL_MSK		0xbfffffffL	/* 		All Interrupt bits */
+#define IS_HW_ERR		BIT_31		/* Interrupt HW Error */
+								/* Bit 30:	reserved */
+#define IS_PA_TO_RX1	BIT_29		/* Packet Arb Timeout Rx1 */
+#define IS_PA_TO_RX2	BIT_28		/* Packet Arb Timeout Rx2 */
+#define IS_PA_TO_TX1	BIT_27		/* Packet Arb Timeout Tx1 */
+#define IS_PA_TO_TX2	BIT_26		/* Packet Arb Timeout Tx2 */
+#define IS_I2C_READY	BIT_25		/* IRQ on end of I2C Tx */
+#define IS_IRQ_SW		BIT_24		/* SW forced IRQ	*/
+#define IS_EXT_REG		BIT_23		/* IRQ from LM80 or PHY (GENESIS only) */
+									/* IRQ from PHY (YUKON only) */
+#define IS_TIMINT		BIT_22		/* IRQ from Timer	*/
+#define IS_MAC1			BIT_21		/* IRQ from MAC 1	*/
+#define IS_LNK_SYNC_M1	BIT_20		/* Link Sync Cnt wrap MAC 1 */
+#define IS_MAC2			BIT_19		/* IRQ from MAC 2	*/
+#define IS_LNK_SYNC_M2	BIT_18		/* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+#define IS_R1_B			BIT_17		/* Q_R1 End of Buffer */
+#define IS_R1_F			BIT_16		/* Q_R1 End of Frame */
+#define IS_R1_C			BIT_15		/* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+#define IS_R2_B			BIT_14		/* Q_R2 End of Buffer */
+#define IS_R2_F			BIT_13		/* Q_R2 End of Frame */
+#define IS_R2_C			BIT_12		/* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+#define IS_XS1_B		BIT_11		/* Q_XS1 End of Buffer */
+#define IS_XS1_F		BIT_10		/* Q_XS1 End of Frame */
+#define IS_XS1_C		BIT_9		/* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+#define IS_XA1_B		BIT_8		/* Q_XA1 End of Buffer */
+#define IS_XA1_F		BIT_7		/* Q_XA1 End of Frame */
+#define IS_XA1_C		BIT_6		/* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+#define IS_XS2_B		BIT_5		/* Q_XS2 End of Buffer */
+#define IS_XS2_F		BIT_4		/* Q_XS2 End of Frame */
+#define IS_XS2_C		BIT_3		/* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+#define IS_XA2_B		BIT_2		/* Q_XA2 End of Buffer */
+#define IS_XA2_F		BIT_1		/* Q_XA2 End of Frame */
+#define IS_XA2_C		BIT_0		/* Q_XA2 Encoding Error */
+
+
+/*	B0_HWE_ISRC	32 bit	HW Error Interrupt Src Reg */
+/*	B0_HWE_IMSK	32 bit	HW Error Interrupt Mask Reg */
+/*	B2_IRQM_HWE_MSK 32 bit	IRQ Moderation HW Error Mask */
+#define IS_ERR_MSK		0x00000fffL	/* 		All Error bits */
+								/* Bit 31..14:	reserved */
+#define IS_IRQ_TIST_OV	BIT_13	/* Time Stamp Timer Overflow (YUKON only) */
+#define IS_IRQ_SENSOR	BIT_12	/* IRQ from Sensor (YUKON only) */
+#define IS_IRQ_MST_ERR	BIT_11	/* IRQ master error detected */
+#define IS_IRQ_STAT		BIT_10	/* IRQ status exception */
+#define IS_NO_STAT_M1	BIT_9	/* No Rx Status from MAC 1 */
+#define IS_NO_STAT_M2	BIT_8	/* No Rx Status from MAC 2 */
+#define IS_NO_TIST_M1	BIT_7	/* No Time Stamp from MAC 1 */
+#define IS_NO_TIST_M2	BIT_6	/* No Time Stamp from MAC 2 */
+#define IS_RAM_RD_PAR	BIT_5	/* RAM Read  Parity Error */
+#define IS_RAM_WR_PAR	BIT_4	/* RAM Write Parity Error */
+#define IS_M1_PAR_ERR	BIT_3	/* MAC 1 Parity Error */
+#define IS_M2_PAR_ERR	BIT_2	/* MAC 2 Parity Error */
+#define IS_R1_PAR_ERR	BIT_1	/* Queue R1 Parity Error */
+#define IS_R2_PAR_ERR	BIT_0	/* Queue R2 Parity Error */
+
+/*	B2_CONN_TYP	 8 bit	Connector type */
+/*	B2_PMD_TYP	 8 bit	PMD type */
+/*	Values of connector and PMD type comply to SysKonnect internal std */
+
+/*	B2_MAC_CFG	 8 bit	MAC Configuration / Chip Revision */
+#define CFG_CHIP_R_MSK	(0xf<<4)	/* Bit 7.. 4: Chip Revision */
+									/* Bit 3.. 2:	reserved */
+#define CFG_DIS_M2_CLK	BIT_1S		/* Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC		BIT_0S		/* MAC Config: 0=2 MACs / 1=1 MAC*/
+
+/*	B2_CHIP_ID	 8 bit 	Chip Identification Number */
+#define CHIP_ID_GENESIS	0x0a		/* Chip ID for GENESIS */
+#define CHIP_ID_YUKON	0xb0		/* Chip ID for YUKON */
+
+/*	B2_FAR		32 bit	Flash-Prom Addr Reg/Cnt */
+#define FAR_ADDR		0x1ffffL	/* Bit 16.. 0:	FPROM Address mask */
+
+/*	B2_LD_CRTL	 8 bit	EPROM loader control register */
+/*	Bits are currently reserved */
+
+/*	B2_LD_TEST	 8 bit	EPROM loader test register */
+								/* Bit 7.. 4:	reserved */
+#define LD_T_ON			BIT_3S	/* Loader Test mode on */
+#define LD_T_OFF		BIT_2S	/* Loader Test mode off */
+#define LD_T_STEP		BIT_1S	/* Decrement FPROM addr. Counter */
+#define LD_START		BIT_0S	/* Start loading FPROM */
+
+/*
+ *	Timer Section
+ */
+/*	B2_TI_CRTL	 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+								/* Bit 7.. 3:	reserved */
+#define TIM_START		BIT_2S	/* Start Timer */
+#define TIM_STOP		BIT_1S	/* Stop  Timer */
+#define TIM_CLR_IRQ		BIT_0S	/* Clear Timer IRQ (!IRQM) */
+
+/*	B2_TI_TEST	 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST	 8 bit	Descriptor Poll Timer Test Reg */
+								/* Bit 7.. 3:	reserved */
+#define TIM_T_ON		BIT_2S	/* Test mode on */
+#define TIM_T_OFF		BIT_1S	/* Test mode off */
+#define TIM_T_STEP		BIT_0S	/* Test step */
+
+/*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
+/*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
+								/* Bit 31..24:	reserved */
+#define DPT_MSK		0x00ffffffL	/* Bit 23.. 0:	Desc Poll Timer Bits */
+
+/*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
+								/* Bit  7.. 2:	reserved */
+#define DPT_START		BIT_1S	/* Start Descriptor Poll Timer */
+#define DPT_STOP		BIT_0S	/* Stop  Descriptor Poll Timer */
+
+/*	B2_E_3			 8 bit 	lower 4 bits used for HW self test result */
+#define B2_E3_RES_MASK	0x0f
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+#define TST_FRC_DPERR_MR	BIT_7S	/* force DATAPERR on MST RD */
+#define TST_FRC_DPERR_MW	BIT_6S	/* force DATAPERR on MST WR */
+#define TST_FRC_DPERR_TR	BIT_5S	/* force DATAPERR on TRG RD */
+#define TST_FRC_DPERR_TW	BIT_4S	/* force DATAPERR on TRG WR */
+#define TST_FRC_APERR_M		BIT_3S	/* force ADDRPERR on MST */
+#define TST_FRC_APERR_T		BIT_2S	/* force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON	BIT_1S	/* Enable  Config Reg WR */
+#define TST_CFG_WRITE_OFF	BIT_0S	/* Disable Config Reg WR */
+
+/*	B2_TST_CTRL2	 8 bit	Test Control Register 2 */
+									/* Bit 7.. 4:	reserved */
+			/* force the following error on the next master read/write	*/
+#define TST_FRC_DPERR_MR64	BIT_3S	/* DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	BIT_2S	/* DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	BIT_1S	/* AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	BIT_0S	/* AddrPERR on 2. phase */
+
+/*	B2_GP_IO	32 bit	General Purpose I/O Register */
+							/* Bit 31..26:	reserved */
+#define GP_DIR_9	BIT_25	/* IO_9 direct, 0=I/1=O */
+#define GP_DIR_8	BIT_24	/* IO_8 direct, 0=I/1=O */
+#define GP_DIR_7	BIT_23	/* IO_7 direct, 0=I/1=O */
+#define GP_DIR_6	BIT_22	/* IO_6 direct, 0=I/1=O */
+#define GP_DIR_5	BIT_21	/* IO_5 direct, 0=I/1=O */
+#define GP_DIR_4	BIT_20	/* IO_4 direct, 0=I/1=O */
+#define GP_DIR_3	BIT_19	/* IO_3 direct, 0=I/1=O */
+#define GP_DIR_2	BIT_18	/* IO_2 direct, 0=I/1=O */
+#define GP_DIR_1	BIT_17	/* IO_1 direct, 0=I/1=O */
+#define GP_DIR_0	BIT_16	/* IO_0 direct, 0=I/1=O */
+						/* Bit 15..10:	reserved */
+#define GP_IO_9		BIT_9	/* IO_9 pin */
+#define GP_IO_8		BIT_8	/* IO_8 pin */
+#define GP_IO_7		BIT_7	/* IO_7 pin */
+#define GP_IO_6		BIT_6	/* IO_6 pin */
+#define GP_IO_5		BIT_5	/* IO_5 pin */
+#define GP_IO_4		BIT_4	/* IO_4 pin */
+#define GP_IO_3		BIT_3	/* IO_3 pin */
+#define GP_IO_2		BIT_2	/* IO_2 pin */
+#define GP_IO_1		BIT_1	/* IO_1 pin */
+#define GP_IO_0		BIT_0	/* IO_0 pin */
+
+/*	B2_I2C_CTRL	32 bit	I2C HW Control Register */
+#define I2C_FLAG		BIT_31		/* Start read/write if WR */
+#define I2C_ADDR		(0x7fffL<<16)	/* Bit 30..16:	Addr to be RD/WR */
+#define I2C_DEV_SEL		(0x7fL<<9)		/* Bit 15.. 9:	I2C Device Select */
+								/* Bit	8.. 5:	reserved	*/
+#define I2C_BURST_LEN	BIT_4		/* Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE	(7L<<1)		/* Bit	3.. 1:	I2C Device Size	*/
+#define I2C_025K_DEV	(0L<<1)		/*		0: 256 Bytes or smal. */
+#define I2C_05K_DEV		(1L<<1)		/* 		1: 512	Bytes	*/
+#define I2C_1K_DEV		(2L<<1)		/*		2: 1024 Bytes	*/
+#define I2C_2K_DEV		(3L<<1)		/*		3: 2048	Bytes	*/
+#define I2C_4K_DEV		(4L<<1)		/*		4: 4096 Bytes	*/
+#define I2C_8K_DEV		(5L<<1)		/*		5: 8192 Bytes	*/
+#define I2C_16K_DEV		(6L<<1)		/*		6: 16384 Bytes	*/
+#define I2C_32K_DEV		(7L<<1)		/*		7: 32768 Bytes	*/
+#define I2C_STOP		BIT_0		/* Interrupt I2C transfer */
+
+/*	B2_I2C_IRQ	32 bit	I2C HW IRQ Register */
+								/* Bit 31.. 1	reserved */
+#define I2C_CLR_IRQ		BIT_0	/* Clear I2C IRQ */
+
+/*	B2_I2C_SW	32 bit (8 bit access)	I2C HW SW Port Register */
+								/* Bit  7.. 3:	reserved */
+#define I2C_DATA_DIR	BIT_2S		/* direction of I2C_DATA */
+#define I2C_DATA		BIT_1S		/* I2C Data Port	*/
+#define I2C_CLK			BIT_0S		/* I2C Clock Port	*/
+
+/*
+ * I2C Address
+ */
+#define I2C_SENS_ADDR	LM80_ADDR	/* I2C Sensor Address, (Volt and Temp)*/
+
+
+/*	B2_BSC_CTRL	 8 bit	Blink Source Counter Control */
+							/* Bit  7.. 2:	reserved */
+#define BSC_START	BIT_1S		/* Start Blink Source Counter */
+#define BSC_STOP	BIT_0S		/* Stop  Blink Source Counter */
+
+/*	B2_BSC_STAT	 8 bit	Blink Source Counter Status */
+							/* Bit  7.. 1:	reserved */
+#define BSC_SRC		BIT_0S		/* Blink Source, 0=Off / 1=On */
+
+/*	B2_BSC_TST	16 bit	Blink Source Counter Test Reg */
+#define BSC_T_ON	BIT_2S		/* Test mode on */
+#define BSC_T_OFF	BIT_1S		/* Test mode off */
+#define BSC_T_STEP	BIT_0S		/* Test step */
+
+
+/*	B3_RAM_ADDR	32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+
+/* RAM Interface Registers */
+/*	B3_RI_CTRL	16 bit	RAM Iface Control Register */
+								/* Bit 15..10:	reserved */
+#define RI_CLR_RD_PERR	BIT_9S	/* Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR	BIT_8S	/* Clear IRQ RAM Write Parity Err*/
+								/* Bit	7.. 2:	reserved */
+#define RI_RST_CLR		BIT_1S	/* Clear RAM Interface Reset */
+#define RI_RST_SET		BIT_0S	/* Set   RAM Interface Reset */
+
+/*	B3_RI_TEST	 8 bit	RAM Iface Test Register */
+								/* Bit 15.. 4:	reserved */
+#define RI_T_EV			BIT_3S	/* Timeout Event occured */
+#define RI_T_ON			BIT_2S	/* Timeout Timer Test On */
+#define RI_T_OFF		BIT_1S	/* Timeout Timer Test Off */
+#define RI_T_STEP		BIT_0S	/* Timeout Timer Step */
+
+/* MAC Arbiter Registers */
+/*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
+								/* Bit 15.. 4:	reserved */
+#define MA_FOE_ON		BIT_3S	/* XMAC Fast Output Enable ON */
+#define MA_FOE_OFF		BIT_2S	/* XMAC Fast Output Enable OFF */
+#define MA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define MA_RST_SET		BIT_0S	/* Set   MAC Arbiter Reset */
+
+/*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
+								/* Bit 15.. 8:	reserved */
+#define MA_ENA_REC_TX2	BIT_7S	/* Enable  Recovery Timer TX2 */
+#define MA_DIS_REC_TX2	BIT_6S	/* Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1	BIT_5S	/* Enable  Recovery Timer TX1 */
+#define MA_DIS_REC_TX1	BIT_4S	/* Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2	BIT_3S	/* Enable  Recovery Timer RX2 */
+#define MA_DIS_REC_RX2	BIT_2S	/* Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1	BIT_1S	/* Enable  Recovery Timer RX1 */
+#define MA_DIS_REC_RX1	BIT_0S	/* Disable Recovery Timer RX1 */
+
+/* Packet Arbiter Registers */
+/*	B3_PA_CTRL	16 bit	Packet Arbiter Ctrl Register */
+								/* Bit 15..14:	reserved */
+#define PA_CLR_TO_TX2	BIT_13S	/* Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1	BIT_12S	/* Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2	BIT_11S	/* Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1	BIT_10S	/* Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2	BIT_9S	/* Enable  Timeout Timer TX2 */
+#define PA_DIS_TO_TX2	BIT_8S	/* Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1	BIT_7S	/* Enable  Timeout Timer TX1 */
+#define PA_DIS_TO_TX1	BIT_6S	/* Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2	BIT_5S	/* Enable  Timeout Timer RX2 */
+#define PA_DIS_TO_RX2	BIT_4S	/* Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1	BIT_3S	/* Enable  Timeout Timer RX1 */
+#define PA_DIS_TO_RX1	BIT_2S	/* Disable Timeout Timer RX1 */
+#define PA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define PA_RST_SET		BIT_0S	/* Set   MAC Arbiter Reset */
+
+#define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+						PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/*	B3_MA_TO_TEST	16 bit	MAC Arbiter Timeout Test Reg */
+/*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
+/*	B3_PA_TEST	16 bit	Packet Arbiter Test Register */
+/*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+#define TX2_T_EV	BIT_15S		/* TX2 Timeout/Recv Event occured */
+#define TX2_T_ON	BIT_14S		/* TX2 Timeout/Recv Timer Test On */
+#define TX2_T_OFF	BIT_13S		/* TX2 Timeout/Recv Timer Tst Off */
+#define TX2_T_STEP	BIT_12S		/* TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV	BIT_11S		/* TX1 Timeout/Recv Event occured */
+#define TX1_T_ON	BIT_10S		/* TX1 Timeout/Recv Timer Test On */
+#define TX1_T_OFF	BIT_9S		/* TX1 Timeout/Recv Timer Tst Off */
+#define TX1_T_STEP	BIT_8S		/* TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV	BIT_7S		/* RX2 Timeout/Recv Event occured */
+#define RX2_T_ON	BIT_6S		/* RX2 Timeout/Recv Timer Test On */
+#define RX2_T_OFF	BIT_5S		/* RX2 Timeout/Recv Timer Tst Off */
+#define RX2_T_STEP	BIT_4S		/* RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV	BIT_3S		/* RX1 Timeout/Recv Event occured */
+#define RX1_T_ON	BIT_2S		/* RX1 Timeout/Recv Timer Test On */
+#define RX1_T_OFF	BIT_1S		/* RX1 Timeout/Recv Timer Tst Off */
+#define RX1_T_STEP	BIT_0S		/* RX1 Timeout/Recv Timer Step */
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/*	TXA_ITI_INI	32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL	32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI	32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL	32 bit	Tx Arb Limit Counter Value */
+								/* Bit 31..24:	reserved */
+#define TXA_MAX_VAL	0x00ffffffL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL	 8 bit	Tx Arbiter Control Register */
+#define TXA_ENA_FSYNC	BIT_7S	/* Enable  force of sync Tx queue */
+#define TXA_DIS_FSYNC	BIT_6S	/* Disable force of sync Tx queue */
+#define TXA_ENA_ALLOC	BIT_5S	/* Enable  alloc of free bandwidth */
+#define TXA_DIS_ALLOC	BIT_4S	/* Disable alloc of free bandwidth */
+#define TXA_START_RC	BIT_3S	/* Start sync Rate Control */
+#define TXA_STOP_RC		BIT_2S	/* Stop  sync Rate Control */
+#define TXA_ENA_ARB		BIT_1S	/* Enable  Tx Arbiter */
+#define TXA_DIS_ARB		BIT_0S	/* Disable Tx Arbiter */
+
+/*	TXA_TEST	 8 bit	Tx Arbiter Test Register */
+								/* Bit 7.. 6:	reserved */
+#define TXA_INT_T_ON	BIT_5S	/* Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF	BIT_4S	/* Tx Arb Interval Timer Test Off */
+#define TXA_INT_T_STEP	BIT_3S	/* Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON	BIT_2S	/* Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF	BIT_1S	/* Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP	BIT_0S	/* Tx Arb Limit Timer Step */
+
+/*	TXA_STAT	 8 bit	Tx Arbiter Status Register */
+								/* Bit 7.. 1:	reserved */
+#define TXA_PRIO_XS		BIT_0S	/* sync queue has prio to send */
+
+/*	Q_BC	32 bit	Current Byte Counter */
+								/* Bit 31..16:	reserved */
+#define BC_MAX			0xffff	/* Bit 15.. 0:	Byte counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR	32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR	32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR	32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR	32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR		32 bit	BMU Control/Status Register */
+								/* Bit 31..25:	reserved */
+#define CSR_SV_IDLE		BIT_24		/* BMU SM Idle */
+								/* Bit 23..22:	reserved */
+#define CSR_DESC_CLR	BIT_21		/* Clear Reset for Descr */
+#define CSR_DESC_SET	BIT_20		/* Set   Reset for Descr */
+#define CSR_FIFO_CLR	BIT_19		/* Clear Reset for FIFO */
+#define CSR_FIFO_SET	BIT_18		/* Set   Reset for FIFO */
+#define CSR_HPI_RUN		BIT_17		/* Release HPI SM */
+#define CSR_HPI_RST		BIT_16		/* Reset   HPI SM to Idle */
+#define CSR_SV_RUN		BIT_15		/* Release Supervisor SM */
+#define CSR_SV_RST		BIT_14		/* Reset   Supervisor SM */
+#define CSR_DREAD_RUN	BIT_13		/* Release Descr Read SM */
+#define CSR_DREAD_RST	BIT_12		/* Reset   Descr Read SM */
+#define CSR_DWRITE_RUN	BIT_11		/* Release Descr Write SM */
+#define CSR_DWRITE_RST	BIT_10		/* Reset   Descr Write SM */
+#define CSR_TRANS_RUN	BIT_9		/* Release Transfer SM */
+#define CSR_TRANS_RST	BIT_8		/* Reset   Transfer SM */
+#define CSR_ENA_POL		BIT_7		/* Enable  Descr Polling */
+#define CSR_DIS_POL		BIT_6		/* Disable Descr Polling */
+#define CSR_STOP		BIT_5		/* Stop  Rx/Tx Queue */
+#define CSR_START		BIT_4		/* Start Rx/Tx Queue */
+#define CSR_IRQ_CL_P	BIT_3		/* (Rx)	Clear Parity IRQ */
+#define CSR_IRQ_CL_B	BIT_2		/* Clear EOB IRQ */
+#define CSR_IRQ_CL_F	BIT_1		/* Clear EOF IRQ */
+#define CSR_IRQ_CL_C	BIT_0		/* Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+						CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+						CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+						CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+						CSR_TRANS_RUN)
+
+/*	Q_F	32 bit	Flag Register */
+									/* Bit 31..28:	reserved */
+#define F_ALM_FULL		BIT_27		/* Rx FIFO: almost full */
+#define F_EMPTY			BIT_27		/* Tx FIFO: empty flag */
+#define F_FIFO_EOF		BIT_26		/* Tag (EOF Flag) bit in FIFO */
+#define F_WM_REACHED	BIT_25		/* Watermark reached */
+									/* reserved */
+#define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 23..16:	# of Qwords in FIFO */
+									/* Bit 15..11: 	reserved */
+#define F_WATER_MARK	0x0007ffL	/* Bit 10.. 0:	Watermark */
+
+/*	Q_T1	32 bit	Test Register 1 */
+/*		Holds four State Machine control Bytes */
+#define SM_CRTL_SV_MSK	(0xffL<<24)	/* Bit 31..24:	Control Supervisor SM */
+#define SM_CRTL_RD_MSK	(0xffL<<16)	/* Bit 23..16:	Control Read Desc SM */
+#define SM_CRTL_WR_MSK	(0xffL<<8)	/* Bit 15.. 8:	Control Write Desc SM */
+#define SM_CRTL_TR_MSK	0xffL		/* Bit	7.. 0:	Control Transfer SM */
+
+/*	Q_T1_TR	 8 bit	Test Register 1 Transfer SM */
+/*	Q_T1_WR	 8 bit	Test Register 1 Write Descriptor SM */
+/*	Q_T1_RD	 8 bit	Test Register 1 Read Descriptor SM */
+/*	Q_T1_SV	 8 bit	Test Register 1 Supervisor SM */
+
+/* The control status byte of each machine looks like ... */
+#define SM_STATE		0xf0	/* Bit 7.. 4:	State which shall be loaded */
+#define SM_LOAD			BIT_3S	/* Load the SM with SM_STATE */
+#define SM_TEST_ON		BIT_2S	/* Switch on SM Test Mode */
+#define SM_TEST_OFF		BIT_1S	/* Go off the Test Mode */
+#define SM_STEP			BIT_0S	/* Step the State Machine */
+/* The encoding of the states is not supported by the Diagnostics Tool */
+
+/*	Q_T2	32 bit	Test Register 2	*/
+								/* Bit 31.. 8:	reserved */
+#define T2_AC_T_ON		BIT_7	/* Address Counter Test Mode on */
+#define T2_AC_T_OFF		BIT_6	/* Address Counter Test Mode off */
+#define T2_BC_T_ON		BIT_5	/* Byte Counter Test Mode on */
+#define T2_BC_T_OFF		BIT_4	/* Byte Counter Test Mode off */
+#define T2_STEP04		BIT_3	/* Inc AC/Dec BC by 4 */
+#define T2_STEP03		BIT_2	/* Inc AC/Dec BC by 3 */
+#define T2_STEP02		BIT_1	/* Inc AC/Dec BC by 2 */
+#define T2_STEP01		BIT_0	/* Inc AC/Dec BC by 1 */
+
+/*	Q_T3	32 bit	Test Register 3	*/
+								/* Bit 31.. 7:	reserved */
+#define T3_MUX_MSK		(7<<4)	/* Bit  6.. 4:	Mux Position */
+								/* Bit  3:	reserved */
+#define T3_VRAM_MSK		7		/* Bit  2.. 0:	Virtual RAM Buffer Address */
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*	RB_START	32 bit	RAM Buffer Start Address */
+/*	RB_END		32 bit	RAM Buffer End Address */
+/*	RB_WP		32 bit	RAM Buffer Write Pointer */
+/*	RB_RP		32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP	32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP	32 bit	Rx Lower Threshold, Pause Pack */
+/*	RB_RX_UTHP	32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP	32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC		32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV		32 bit	RAM Buffer Level Register */
+				/* Bit 31..19:	reserved */
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+								/* Bit 7.. 4:	reserved */
+#define RB_PC_DEC		BIT_3S	/* Packet Counter Decrem */
+#define RB_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define RB_PC_T_OFF		BIT_1S	/* Packet Counter Tst Off */
+#define RB_PC_INC		BIT_0S	/* Packet Counter Increm */
+
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+							/* Bit 7:	reserved */
+#define RB_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define RB_WP_T_OFF		BIT_5S	/* Write Pointer Test Off */
+#define RB_WP_INC		BIT_4S	/* Write Pointer Increm */
+								/* Bit 3:	reserved */
+#define RB_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define RB_RP_T_OFF		BIT_1S	/* Read Pointer Test Off */
+#define RB_RP_DEC		BIT_0S	/* Read Pointer Decrement */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+								/* Bit 7.. 6:	reserved */
+#define RB_ENA_STFWD	BIT_5S	/* Enable  Store & Forward */
+#define RB_DIS_STFWD	BIT_4S	/* Disable Store & Forward */
+#define RB_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define RB_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define RB_RST_CLR		BIT_1S	/* Clear RAM Buf STM Reset */
+#define RB_RST_SET		BIT_0S	/* Set   RAM Buf STM Reset */
+
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+
+/*	RX_MFF_EA	32 bit	Receive MAC FIFO End Address */
+/*	RX_MFF_WP	32 bit 	Receive MAC FIFO Write Pointer */
+/*	RX_MFF_RP	32 bit	Receive MAC FIFO Read Pointer */
+/*	RX_MFF_PC	32 bit	Receive MAC FIFO Packet Counter */
+/*	RX_MFF_LEV	32 bit	Receive MAC FIFO Level */
+/*	TX_MFF_EA	32 bit	Transmit MAC FIFO End Address */
+/*	TX_MFF_WP	32 bit 	Transmit MAC FIFO Write Pointer */
+/*	TX_MFF_WSP	32 bit	Transmit MAC FIFO WR Shadow Pointer */
+/*	TX_MFF_RP	32 bit	Transmit MAC FIFO Read Pointer */
+/*	TX_MFF_PC	32 bit	Transmit MAC FIFO Packet Cnt */
+/*	TX_MFF_LEV	32 bit	Transmit MAC FIFO Level */
+								/* Bit 31.. 6:	reserved */
+#define MFF_MSK			0x007fL	/* Bit	5.. 0:	MAC FIFO Address/Ptr Bits */
+
+/*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
+								/* Bit 15..14:	reserved */
+#define MFF_ENA_RDY_PAT	BIT_13S		/* Enable  Ready Patch */
+#define MFF_DIS_RDY_PAT	BIT_12S		/* Disable Ready Patch */
+#define MFF_ENA_TIM_PAT	BIT_11S		/* Enable  Timing Patch */
+#define MFF_DIS_TIM_PAT	BIT_10S		/* Disable Timing Patch */
+#define MFF_ENA_ALM_FUL	BIT_9S		/* Enable  AlmostFull Sign */
+#define MFF_DIS_ALM_FUL	BIT_8S		/* Disable AlmostFull Sign */
+#define MFF_ENA_PAUSE	BIT_7S		/* Enable  Pause Signaling */
+#define MFF_DIS_PAUSE	BIT_6S		/* Disable Pause Signaling */
+#define MFF_ENA_FLUSH	BIT_5S		/* Enable  Frame Flushing */
+#define MFF_DIS_FLUSH	BIT_4S		/* Disable Frame Flushing */
+#define MFF_ENA_TIST	BIT_3S		/* Enable  Time Stamp Gener */
+#define MFF_DIS_TIST	BIT_2S		/* Disable Time Stamp Gener */
+#define MFF_CLR_INTIST	BIT_1S		/* Clear IRQ No Time Stamp */
+#define MFF_CLR_INSTAT	BIT_0S		/* Clear IRQ No Status */
+
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+
+/*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
+#define MFF_CLR_PERR	BIT_15S		/* Clear Parity Error IRQ */
+								/* Bit 14:	reserved */
+#define MFF_ENA_PKT_REC	BIT_13S		/* Enable  Packet Recovery */
+#define MFF_DIS_PKT_REC BIT_12S		/* Disable Packet Recovery */
+/*	MFF_ENA_TIM_PAT	 (see RX_MFF_CTRL1) Bit 11:	Enable  Timing Patch */
+/*	MFF_DIS_TIM_PAT	 (see RX_MFF_CTRL1) Bit 10:	Disable Timing Patch */
+/*	MFF_ENA_ALM_FUL	 (see RX_MFF_CTRL1) Bit	 9:	Enable  Almost Full Sign */
+/*	MFF_DIS_ALM_FUL	 (see RX_MFF_CTRL1) Bit	 8:	Disable Almost Full Sign */
+#define MFF_ENA_W4E		BIT_7S		/* Enable  Wait for Empty */
+#define MFF_DIS_W4E		BIT_6S		/* Disable Wait for Empty */
+/*	MFF_ENA_FLUSH	 (see RX_MFF_CTRL1) Bit	 5:	Enable  Frame Flushing */
+/*	MFF_DIS_FLUSH	 (see RX_MFF_CTRL1) Bit	 4:	Disable Frame Flushing */
+#define MFF_ENA_LOOPB	BIT_3S		/* Enable  Loopback */
+#define MFF_DIS_LOOPB	BIT_2S		/* Disable Loopback */
+#define MFF_CLR_MAC_RST	BIT_1S		/* Clear XMAC Reset */
+#define MFF_SET_MAC_RST	BIT_0S		/* Set   XMAC Reset */
+
+#define MFF_TX_CTRL_DEF	(MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/*	RX_MFF_TST2	 	 8 bit	Receive MAC FIFO Test Register 2 */
+/*	TX_MFF_TST2	 	 8 bit	Transmit MAC FIFO Test Register 2 */
+								/* Bit 7:	reserved */
+#define MFF_WSP_T_ON	BIT_6S	/* Tx: Write Shadow Ptr TestOn */
+#define MFF_WSP_T_OFF	BIT_5S	/* Tx: Write Shadow Ptr TstOff */
+#define MFF_WSP_INC		BIT_4S	/* Tx: Write Shadow Ptr Increment */
+#define MFF_PC_DEC		BIT_3S	/* Packet Counter Decrement */
+#define MFF_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define MFF_PC_T_OFF	BIT_1S	/* Packet Counter Test Off */
+#define MFF_PC_INC		BIT_0S	/* Packet Counter Increment */
+
+/*	RX_MFF_TST1	 	 8 bit	Receive MAC FIFO Test Register 1 */
+/*	TX_MFF_TST1	 	 8 bit	Transmit MAC FIFO Test Register 1 */
+					/* Bit 7:	reserved */
+#define MFF_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define MFF_WP_T_OFF	BIT_5S	/* Write Pointer Test Off */
+#define MFF_WP_INC		BIT_4S	/* Write Pointer Increm */
+							/* Bit 3:	reserved */
+#define MFF_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define MFF_RP_T_OFF	BIT_1S	/* Read Pointer Test Off */
+#define MFF_RP_DEC		BIT_0S	/* Read Pointer Decrement */
+
+/*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
+/*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
+								/* Bit 7..4:	reserved */
+#define MFF_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define MFF_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define MFF_RST_CLR		BIT_1S	/* Clear MAC FIFO Reset */
+#define MFF_RST_SET		BIT_0S	/* Set   MAC FIFO Reset */
+
+
+/*	Link LED Counter Registers (GENESIS only) */
+
+/*	RX_LED_CTRL		 8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL		 8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
+							/* Bit 7.. 3:	reserved */
+#define LED_START		BIT_2S	/* Start Timer */
+#define LED_STOP		BIT_1S	/* Stop Timer */
+#define LED_STATE		BIT_0S	/* Rx/Tx: LED State, 1=LED on */
+#define LED_CLR_IRQ		BIT_0S	/* Lnk: 	Clear Link IRQ */
+
+/*	RX_LED_TST		 8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST		 8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
+							/* Bit 7.. 3:	reserved */
+#define LED_T_ON		BIT_2S	/* LED Counter Test mode On */
+#define LED_T_OFF		BIT_1S	/* LED Counter Test mode Off */
+#define LED_T_STEP		BIT_0S	/* LED Counter Step */
+
+/*	LNK_LED_REG	 	 8 bit	Link LED Register */
+								/* Bit 7.. 6:	reserved */
+#define LED_BLK_ON		BIT_5S	/* Link LED Blinking On */
+#define LED_BLK_OFF		BIT_4S	/* Link LED Blinking Off */
+#define LED_SYNC_ON		BIT_3S	/* Use Sync Wire to switch LED */
+#define LED_SYNC_OFF	BIT_2S	/* Disable Sync Wire Input */
+#define LED_ON			BIT_1S	/* switch LED on */
+#define LED_OFF			BIT_0S	/* switch LED off */
+
+/*	Receive and Transmit GMAC FIFO Registers (YUKON only) */
+
+/*	RX_GMF_EA		32 bit	Rx GMAC FIFO End Address */
+/*	RX_GMF_AF_THR	32 bit	Rx GMAC FIFO Almost Full Thresh. */
+/*	RX_GMF_WP		32 bit 	Rx GMAC FIFO Write Pointer */
+/*	RX_GMF_WLEV		32 bit 	Rx GMAC FIFO Write Level */
+/*	RX_GMF_RP		32 bit 	Rx GMAC FIFO Read Pointer */
+/*	RX_GMF_RLEV		32 bit 	Rx GMAC FIFO Read Level */
+/*	TX_GMF_EA		32 bit	Tx GMAC FIFO End Address */
+/*	TX_GMF_AE_THR	32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+/*	TX_GMF_WP		32 bit 	Tx GMAC FIFO Write Pointer */
+/*	TX_GMF_WSP		32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+/*	TX_GMF_WLEV		32 bit 	Tx GMAC FIFO Write Level */
+/*	TX_GMF_RP		32 bit 	Tx GMAC FIFO Read Pointer */
+/*	TX_GMF_RSTP		32 bit 	Tx GMAC FIFO Restart Pointer */
+/*	TX_GMF_RLEV		32 bit 	Tx GMAC FIFO Read Level */
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+						/* Bits 31..15:	reserved */
+#define GMF_WP_TST_ON	BIT_14		/* Write Pointer Test On */
+#define GMF_WP_TST_OFF	BIT_13		/* Write Pointer Test Off */
+#define GMF_WP_STEP		BIT_12		/* Write Pointer Step/Increment */
+						/* Bit 11:	reserved */
+#define GMF_RP_TST_ON	BIT_10		/* Read Pointer Test On */
+#define GMF_RP_TST_OFF	BIT_9		/* Read Pointer Test Off */
+#define GMF_RP_STEP		BIT_8		/* Read Pointer Step/Increment */
+#define GMF_RX_F_FL_ON	BIT_7		/* Rx FIFO Flush Mode On */
+#define GMF_RX_F_FL_OFF	BIT_6		/* Rx FIFO Flush Mode Off */
+#define GMF_CLI_RX_FO	BIT_5		/* Clear IRQ Rx FIFO Overrun */
+#define GMF_CLI_RX_FC	BIT_4		/* Clear IRQ Rx Frame Complete */
+#define GMF_OPER_ON		BIT_3		/* Operational Mode On */
+#define GMF_OPER_OFF	BIT_2		/* Operational Mode Off */
+#define GMF_RST_CLR		BIT_1		/* Clear GMAC FIFO Reset */
+#define GMF_RST_SET		BIT_0		/* Set   GMAC FIFO Reset */
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+						/* Bits 31..19:	reserved */
+#define GMF_WSP_TST_ON	BIT_18		/* Write Shadow Pointer Test On */
+#define GMF_WSP_TST_OFF	BIT_17		/* Write Shadow Pointer Test Off */
+#define GMF_WSP_STEP	BIT_16		/* Write Shadow Pointer Step/Increment */
+						/* Bits 15..7: same as for RX_GMF_CTRL_T */
+#define GMF_CLI_TX_FU	BIT_6		/* Clear IRQ Tx FIFO Underrun */
+#define GMF_CLI_TX_FC	BIT_5		/* Clear IRQ Tx Frame Complete */
+#define GMF_CLI_TX_PE	BIT_4		/* Clear IRQ Tx Parity Error */
+						/* Bits 3..0: same as for RX_GMF_CTRL_T */
+
+#define GMF_RX_CTRL_DEF		(GMF_OPER_ON | GMF_RX_F_FL_ON)
+#define GMF_TX_CTRL_DEF		GMF_OPER_ON
+
+#define RX_GMF_FL_THR_DEF	0x0a	/* Rx GMAC FIFO Flush Threshold default */
+
+/*	GMAC_TI_ST_CTRL		  8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+								/* Bit 7.. 3:	reserved */
+#define GMT_ST_START	BIT_2S		/* Start Time Stamp Timer */
+#define GMT_ST_STOP		BIT_1S		/* Stop  Time Stamp Timer */
+#define GMT_ST_CLR_IRQ	BIT_0S		/* Clear Time Stamp Timer IRQ */
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+						/* Bits 31.. 8:	reserved */
+#define GMC_H_BURST_ON	BIT_7		/* Half Duplex Burst Mode On */
+#define GMC_H_BURST_OFF	BIT_6		/* Half Duplex Burst Mode Off */
+#define GMC_F_LOOPB_ON	BIT_5		/* FIFO Loopback On */
+#define GMC_F_LOOPB_OFF	BIT_4		/* FIFO Loopback Off */
+#define GMC_PAUSE_ON	BIT_3		/* Pause On */
+#define GMC_PAUSE_OFF	BIT_2		/* Pause Off */
+#define GMC_RST_CLR		BIT_1		/* Clear GMAC Reset */
+#define GMC_RST_SET		BIT_0		/* Set   GMAC Reset */
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+						/* Bits 31..29:	reserved */
+#define GPC_SEL_BDT		BIT_28	/* Select Bi-Dir. Transfer for MDC/MDIO */
+#define GPC_INT_POL_HI	BIT_27	/* IRQ Polarity is Active HIGH */
+#define GPC_75_OHM		BIT_26	/* Use 75 Ohm Termination instead of 50 */
+#define GPC_DIS_FC		BIT_25	/* Disable Automatic Fiber/Copper Detection */
+#define GPC_DIS_SLEEP	BIT_24	/* Disable Energy Detect */
+#define GPC_HWCFG_M_3	BIT_23	/* HWCFG_MODE[3] */
+#define GPC_HWCFG_M_2	BIT_22	/* HWCFG_MODE[2] */
+#define GPC_HWCFG_M_1	BIT_21	/* HWCFG_MODE[1] */
+#define GPC_HWCFG_M_0	BIT_20	/* HWCFG_MODE[0] */
+#define GPC_ANEG_0		BIT_19	/* ANEG[0] */
+#define GPC_ENA_XC		BIT_18	/* Enable MDI crossover */
+#define GPC_DIS_125		BIT_17	/* Disable 125 MHz clock */
+#define GPC_ANEG_3		BIT_16	/* ANEG[3] */
+#define GPC_ANEG_2		BIT_15	/* ANEG[2] */
+#define GPC_ANEG_1		BIT_14	/* ANEG[1] */
+#define GPC_ENA_PAUSE	BIT_13	/* Enable Pause (SYM_OR_REM) */
+#define GPC_PHYADDR_4	BIT_12	/* Bit 4 of Phy Addr */
+#define GPC_PHYADDR_3	BIT_11	/* Bit 3 of Phy Addr */
+#define GPC_PHYADDR_2	BIT_10	/* Bit 2 of Phy Addr */
+#define GPC_PHYADDR_1	BIT_9	/* Bit 1 of Phy Addr */
+#define GPC_PHYADDR_0	BIT_8	/* Bit 0 of Phy Addr */
+						/* Bits  7..2:	reserved */
+#define GPC_RST_CLR		BIT_1	/* Clear GPHY Reset */
+#define GPC_RST_SET		BIT_0	/* Set   GPHY Reset */
+
+#define GPC_HWCFG_GMII_COP	(GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_HWCFG_GMII_FIB	(				 GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_ANEG_ADV_ALL_M	(GPC_ANEG_3 | GPC_ANEG_2 | \
+							 GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF	0
+#define GPC_FRC10MBIT_FULL	GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF	GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL	(GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF	GPC_ANEG_2
+#define GPC_ADV_1000_FULL	GPC_ANEG_3
+#define GPC_ADV_ALL			(GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER	0
+#define GPC_FORCE_SLAVE		GPC_ANEG_0
+#define GPC_PREF_MASTER		GPC_ANEG_1
+#define GPC_PREF_SLAVE		(GPC_ANEG_1 | GPC_ANEG_0)
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+#define GM_IS_TX_CO_OV	BIT_5		/* Transmit Counter Overflow IRQ */
+#define GM_IS_RX_CO_OV	BIT_4		/* Receive Counter Overflow IRQ */
+#define GM_IS_TX_FF_UR	BIT_3		/* Transmit FIFO Underrun */
+#define GM_IS_TX_COMPL	BIT_2		/* Frame Transmission Complete */
+#define GM_IS_RX_FF_OR	BIT_1		/* Receive FIFO Overrun */
+#define GM_IS_RX_COMPL	BIT_0		/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK	(GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \
+						GM_IS_TX_FF_UR)
+
+/*	GMAC_LINK_CTRL		16 bit	GMAC Link Control Reg (YUKON only) */
+						/* Bits 15.. 2:	reserved */
+#define GMLC_RST_CLR	BIT_1S		/* Clear GMAC Link Reset */
+#define GMLC_RST_SET	BIT_0S		/* Set   GMAC Link Reset */
+
+
+/*	WOL_CTRL_STAT		16 bit	WOL Control/Status Reg */
+#define WOL_CTL_LINK_CHG_OCC			BIT_15S
+#define WOL_CTL_MAGIC_PKT_OCC			BIT_14S
+#define WOL_CTL_PATTERN_OCC				BIT_13S
+
+#define WOL_CTL_CLEAR_RESULT			BIT_12S
+
+#define WOL_CTL_ENA_PME_ON_LINK_CHG		BIT_11S
+#define WOL_CTL_DIS_PME_ON_LINK_CHG		BIT_10S
+#define WOL_CTL_ENA_PME_ON_MAGIC_PKT	BIT_9S
+#define WOL_CTL_DIS_PME_ON_MAGIC_PKT	BIT_8S
+#define WOL_CTL_ENA_PME_ON_PATTERN		BIT_7S
+#define WOL_CTL_DIS_PME_ON_PATTERN		BIT_6S
+
+#define WOL_CTL_ENA_LINK_CHG_UNIT		BIT_5S
+#define WOL_CTL_DIS_LINK_CHG_UNIT		BIT_4S
+#define WOL_CTL_ENA_MAGIC_PKT_UNIT		BIT_3S
+#define WOL_CTL_DIS_MAGIC_PKT_UNIT		BIT_2S
+#define WOL_CTL_ENA_PATTERN_UNIT		BIT_1S
+#define WOL_CTL_DIS_PATTERN_UNIT		BIT_0S
+
+#define WOL_CTL_DEFAULT				\
+	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
+	WOL_CTL_DIS_PME_ON_PATTERN |	\
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
+	WOL_CTL_DIS_LINK_CHG_UNIT |		\
+	WOL_CTL_DIS_PATTERN_UNIT |		\
+	WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/*	WOL_MATCH_CTL		 8 bit	WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)				(BIT_0 << (x))
+
+#define SK_NUM_WOL_PATTERN		7
+#define SK_PATTERN_PER_WORD		4
+#define SK_BITMASK_PATTERN		7
+#define SK_POW_PATTERN_LENGTH	128
+
+#define WOL_LENGTH_MSK		0x7f
+#define WOL_LENGTH_SHIFT	8
+
+
+/* Receive and Transmit Descriptors ******************************************/
+
+/* Transmit Descriptor struct */
+typedef	struct s_HwTxd {
+	SK_U32 volatile	TxCtrl;	/* Transmit Buffer Control Field */
+	SK_U32	TxNext;			/* Physical Address Pointer to the next TxD */
+	SK_U32	TxAdrLo;		/* Physical Tx Buffer Address lower dword */
+	SK_U32	TxAdrHi;		/* Physical Tx Buffer Address upper dword */
+	SK_U32	TxStat;			/* Transmit Frame Status Word */
+#ifndef	SK_USE_REV_DESC
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
+#endif	/* SK_USE_REV_DESC */
+	SK_U32  TxRes2;			/* 32 bit reserved field */
+} SK_HWTXD;
+
+/* Receive Descriptor struct */
+typedef	struct s_HwRxd {
+	SK_U32 volatile RxCtrl;	/* Receive Buffer Control Field */
+	SK_U32	RxNext;			/* Physical Address Pointer to the next RxD */
+	SK_U32	RxAdrLo;		/* Physical Rx Buffer Address lower dword */
+	SK_U32	RxAdrHi;		/* Physical Rx Buffer Address upper dword */
+	SK_U32	RxStat;			/* Receive Frame Status Word */
+	SK_U32	RxTiSt;			/* Receive Time Stamp (from XMAC on GENESIS) */
+#ifndef	SK_USE_REV_DESC
+	SK_U16	RxTcpSum1;		/* TCP Checksum 1 */
+	SK_U16	RxTcpSum2;		/* TCP Checksum 2 */
+	SK_U16	RxTcpSp1;		/* TCP Checksum Calculation Start Position 1 */
+	SK_U16	RxTcpSp2;		/* TCP Checksum Calculation Start Position 2 */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	RxTcpSum2;		/* TCP Checksum 2 */
+	SK_U16	RxTcpSum1;		/* TCP Checksum 1 */
+	SK_U16	RxTcpSp2;		/* TCP Checksum Calculation Start Position 2 */
+	SK_U16	RxTcpSp1;		/* TCP Checksum Calculation Start Position 1 */
+#endif	/* SK_USE_REV_DESC */
+} SK_HWRXD;
+
+/*
+ * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
+ * should set the define SK_USE_REV_DESC.
+ * Structures are 'normaly' not endianess dependent. But in
+ * this case the SK_U16 fields are bound to bit positions inside the
+ * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
+ * The bit positions inside a DWord are of course endianess dependent and
+ * swaps if the DWord is swapped by the hardware.
+ */
+
+
+/* Descriptor Bit Definition */
+/*	TxCtrl		Transmit Buffer Control Field */
+/*	RxCtrl		Receive  Buffer Control Field */
+#define BMU_OWN			BIT_31	/* OWN bit: 0=host/1=BMU */
+#define BMU_STF			BIT_30	/* Start of Frame */
+#define BMU_EOF			BIT_29	/* End of Frame */
+#define BMU_IRQ_EOB		BIT_28	/* Req "End of Buffer" IRQ */
+#define BMU_IRQ_EOF		BIT_27	/* Req "End of Frame" IRQ */
+/* TxCtrl specific bits */
+#define BMU_STFWD		BIT_26	/* (Tx)	Store & Forward Frame */
+#define BMU_NO_FCS		BIT_25	/* (Tx) Disable MAC FCS (CRC) generation */
+#define BMU_SW			BIT_24	/* (Tx)	1 bit res. for SW use */
+/* RxCtrl specific bits */
+#define BMU_DEV_0		BIT_26	/* (Rx)	Transfer data to Dev0 */
+#define BMU_STAT_VAL	BIT_25	/* (Rx)	Rx Status Valid */
+#define BMU_TIST_VAL	BIT_24	/* (Rx)	Rx TimeStamp Valid */
+								/* Bit 23..16:	BMU Check Opcodes */
+#define BMU_CHECK		(0x55L<<16)	/* Default BMU check */
+#define BMU_TCP_CHECK	(0x56L<<16)	/* Descr with TCP ext */
+#define BMU_UDP_CHECK	(0x57L<<16)	/* Descr with UDP ext (YUKON only) */
+#define BMU_BBC			0xFFFFL	/* Bit 15.. 0:	Buffer Byte Counter */
+
+/*	TxStat		Transmit Frame Status Word */
+/*	RxStat		Receive Frame Status Word */
+/*
+ *Note: TxStat is reserved for ASIC loopback mode only
+ *
+ *	The Bits of the Status words are defined in xmac_ii.h
+ *	(see XMR_FS bits)
+ */
+
+/* other defines *************************************************************/
+
+/*
+ * FlashProm specification
+ */
+#define MAX_PAGES	0x20000L	/* Every byte has a single page */
+#define MAX_FADDR	1			/* 1 byte per page */
+#define SKFDDI_PSZ	8			/* address PROM size */
+
+/* macros ********************************************************************/
+
+/*
+ * Receive and Transmit Queues
+ */
+#define Q_R1	0x0000		/* Receive Queue 1 */
+#define Q_R2	0x0080		/* Receive Queue 2 */
+#define Q_XS1	0x0200		/* Synchronous Transmit Queue 1 */
+#define Q_XA1	0x0280		/* Asynchronous Transmit Queue 1 */
+#define Q_XS2	0x0300		/* Synchronous Transmit Queue 2 */
+#define Q_XA2	0x0380		/* Asynchronous Transmit Queue 2 */
+
+/*
+ *	Macro Q_ADDR()
+ *
+ *	Use this macro to access the Receive and Transmit Queue Registers.
+ *
+ * para:
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *				Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *
+ * usage	SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal)
+ */
+#define Q_ADDR(Queue, Offs)	(B8_Q_REGS + (Queue) + (Offs))
+
+/*
+ *	Macro RB_ADDR()
+ *
+ *	Use this macro to access the RAM Buffer Registers.
+ *
+ * para:
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *				Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *
+ * usage	SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal)
+ */
+#define RB_ADDR(Queue, Offs)	(B16_RAM_REGS + (Queue) + (Offs))
+
+
+/*
+ * MAC Related Registers
+ */
+#define MAC_1		0	/* belongs to the port near the slot */
+#define MAC_2		1	/* belongs to the port far away from the slot */
+
+/*
+ *	Macro MR_ADDR()
+ *
+ *	Use this macro to access a MAC Related Registers inside the ASIC.
+ *
+ * para:
+ *	Mac		MAC to access.
+ *				Values: MAC_1, MAC_2
+ *	Offs	MAC register offset.
+ *				Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG,
+ *						TX_MFF_EA, TX_MFF_WP ... TX_LED_TST
+ *
+ * usage	SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal)
+ */
+#define MR_ADDR(Mac, Offs)	(((Mac) << 7) + (Offs))
+
+#ifdef	SK_LITTLE_ENDIAN
+#define XM_WORD_LO	0
+#define XM_WORD_HI	1
+#else	/* !SK_LITTLE_ENDIAN */
+#define XM_WORD_LO	1
+#define XM_WORD_HI	0
+#endif	/* !SK_LITTLE_ENDIAN */
+
+
+/*
+ * macros to access the XMAC (GENESIS only)
+ *
+ * XM_IN16(),		to read a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_OUT16(),		to write a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_IN32(),		to read a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_OUT32(),		to write a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_INADDR(),		to read a network address register (e.g. XM_SRC_CHK)
+ * XM_OUTADDR(),	to write a network address register (e.g. XM_SRC_CHK)
+ * XM_INHASH(),		to read the XM_HSM_CHK register
+ * XM_OUTHASH()		to write the XM_HSM_CHK register
+ *
+ * para:
+ *	Mac		XMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		XMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
+ *
+ * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
+ */
+
+#define XMA(Mac, Reg)									\
+	((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1))
+
+#define XM_IN16(IoC, Mac, Reg, pVal)					\
+	SK_IN16((IoC), XMA((Mac), (Reg)), (pVal))
+
+#define XM_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
+
+#define XM_IN32(IoC, Mac, Reg, pVal) {					\
+	SK_IN16((IoC), XMA((Mac), (Reg)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]);		\
+}
+
+#define XM_OUT32(IoC, Mac, Reg, Val) {										\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */
+
+#define XM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+}
+
+#define XM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word);			\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
+}
+
+/*
+ * macros to access the GMAC (YUKON only)
+ *
+ * GM_IN16(),		to read  a 16 bit register (e.g. GM_GP_STAT)
+ * GM_OUT16(),		to write a 16 bit register (e.g. GM_GP_CTRL)
+ * GM_IN32(),		to read  a 32 bit register (e.g. GM_)
+ * GM_OUT32(),		to write a 32 bit register (e.g. GM_)
+ * GM_INADDR(),		to read  a network address register (e.g. GM_SRC_ADDR_1L)
+ * GM_OUTADDR(),	to write a network address register (e.g. GM_SRC_ADDR_2L)
+ * GM_INHASH(),		to read  the GM_MC_ADDR_H1 register
+ * GM_OUTHASH()		to write the GM_MC_ADDR_H1 register
+ *
+ * para:
+ *	Mac		GMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		GMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
+ *
+ * usage:	GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value);
+ */
+
+#define GMA(Mac, Reg)									\
+	((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg))
+
+#define GM_IN16(IoC, Mac, Reg, pVal)					\
+	SK_IN16((IoC), GMA((Mac), (Reg)), (pVal))
+
+#define GM_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (Val))
+
+#define GM_IN32(IoC, Mac, Reg, pVal) {					\
+	SK_IN16((IoC), GMA((Mac), (Reg)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]);		\
+}
+
+#define GM_OUT32(IoC, Mac, Reg, Val) {										\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+#define GM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+}
+
+#define GM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word);		\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
+}
+
+/*
+ * Different MAC Types
+ */
+#define SK_MAC_XMAC		0	/* Xaqti XMAC II */
+#define SK_MAC_GMAC		1	/* Marvell GMAC */
+
+/*
+ * Different PHY Types
+ */
+#define SK_PHY_XMAC			0	/* integrated in XMAC II */
+#define SK_PHY_BCOM			1	/* Broadcom BCM5400 */
+#define SK_PHY_LONE			2	/* Level One LXT1000 */
+#define SK_PHY_NAT			3	/* National DP83891 */
+#define SK_PHY_MARV_COPPER	4	/* Marvell 88E1011S */
+#define SK_PHY_MARV_FIBER	5	/* Marvell 88E1011S working on fiber */
+
+/*
+ * PHY addresses (bits 12..8 of PHY address reg)
+ */
+#define PHY_ADDR_XMAC	(0<<8)
+#define PHY_ADDR_BCOM	(1<<8)
+#define PHY_ADDR_LONE	(3<<8)
+#define PHY_ADDR_NAT	(0<<8)
+
+/* GPHY address (bits 15..11 of SMI control reg) */
+#define PHY_ADDR_MARV	0
+
+/*
+ * macros to access the PHY
+ *
+ * PHY_READ()		read a 16 bit value from the PHY
+ * PHY_WRITE()		write a 16 bit value to the PHY
+ *
+ * para:
+ * 	IoC		I/O context needed for SK I/O macros
+ * 	pPort	Pointer to port struct for PhyAddr
+ * 	Mac		XMAC to access		values: MAC_1 or MAC_2
+ * 	PhyReg	PHY Register to read or write
+ * 	(p)Val	Value or pointer to the value which should be read or
+ *			written.
+ *
+ * usage:	PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
+ * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never
+ *          comes back. This is checked in DEBUG mode.
+ */
+#ifndef DEBUG
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
+}
+#else
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+	int __i = 0;														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+			__i++;														\
+			if (__i > 100000) {											\
+				SK_DBG_PRINTF("*****************************\n");		\
+				SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n");		\
+				SK_DBG_PRINTF("*****************************\n");		\
+				break;													\
+			}															\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
+}
+#endif /* DEBUG */
+
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {						\
+	SK_U16 Mmu;															\
+																		\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
+}
+
+/*
+ *	Macro PCI_C()
+ *
+ *	Use this macro to access PCI config register from the I/O space.
+ *
+ * para:
+ *	Addr	PCI configuration register to access.
+ *			Values:	PCI_VENDOR_ID ... PCI_VPD_ADR_REG,
+ *
+ * usage	SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal);
+ */
+#define PCI_C(Addr)	(B7_CFG_SPC + (Addr))	/* PCI Config Space */
+
+/*
+ *	Macro SK_HW_ADDR(Base, Addr)
+ *
+ *	Calculates the effective HW address
+ *
+ * para:
+ *	Base	I/O or memory base address
+ *	Addr	Address offset
+ *
+ * usage:	May be used in SK_INxx and SK_OUTxx macros
+ *		#define SK_IN8(pAC, Addr, pVal) ...\
+ *			*pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr)))
+ */
+#ifdef	SK_MEM_MAPPED_IO
+#define SK_HW_ADDR(Base, Addr)	((Base) + (Addr))
+#else	/* SK_MEM_MAPPED_IO */
+#define SK_HW_ADDR(Base, Addr)	\
+			((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0)))
+#endif	/* SK_MEM_MAPPED_IO */
+
+#define SZ_LONG	(sizeof(SK_U32))
+
+/*
+ *	Macro SK_HWAC_LINK_LED()
+ *
+ *	Use this macro to set the link LED mode.
+ * para:
+ *	pAC		Pointer to adapter context struct
+ *	IoC		I/O context needed for SK I/O macros
+ *  Port	Port number
+ *	Mode	Mode to set for this LED
+ */
+#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_LED_REG), Mode);
+
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEHW_H */
diff --git a/drivers/net/sk98lin/h/skgehwt.h b/drivers/net/sk98lin/h/skgehwt.h
new file mode 100644
index 0000000..8aa9edd
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehwt.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Name:	skhwt.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 1999/11/22 13:54:24 $
+ * Purpose:	Defines for the hardware timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgehwt.h,v $
+ *	Revision 1.5  1999/11/22 13:54:24  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.4  1998/08/19 09:50:58  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.3  1998/08/14 07:09:29  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.2  1998/08/07 12:54:21  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.1  1998/08/07 09:32:58  gklug
+ *	first version
+ *
+ *
+ *
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEHWT.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKGEHWT_H_
+#define _SKGEHWT_H_
+
+/*
+ * SK Hardware Timer
+ * - needed wherever the HWT module is used
+ * - use in Adapters context name pAC->Hwt
+ */
+typedef	struct s_Hwt {
+	SK_U32		TStart ;	/* HWT start */
+	SK_U32		TStop ;		/* HWT stop */
+	int		TActive ;	/* HWT: flag : active/inactive */
+} SK_HWT;
+
+extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time);
+extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc);
+extern SK_U32 SkHwtRead(SK_AC *pAC,SK_IOC Ioc);
+extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc);
+#endif	/* _SKGEHWT_H_ */
diff --git a/drivers/net/sk98lin/h/skgei2c.h b/drivers/net/sk98lin/h/skgei2c.h
new file mode 100644
index 0000000..e639f73
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgei2c.h
@@ -0,0 +1,299 @@
+/******************************************************************************
+ *
+ * Name:	skgei2c.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.23 $
+ * Date:	$Date: 2002/12/19 14:34:27 $
+ * Purpose:	Special GEnesis defines for TWSI
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgei2c.h,v $
+ *	Revision 1.23  2002/12/19 14:34:27  rschmidt
+ *	Added cast in macros SK_I2C_SET_BIT() and SK_I2C_CLR_BIT()
+ *	Editorial changes (TWSI)
+ *
+ *	Revision 1.22  2002/10/14 16:45:56  rschmidt
+ *	Editorial changes (TWSI)
+ *
+ *	Revision 1.21  2002/08/13 08:42:24  rschmidt
+ *	Changed define for SK_MIN_SENSORS back to 5
+ *	Merged defines for PHY PLL 3V3 voltage (A and B)
+ *	Editorial changes
+ *
+ *	Revision 1.20  2002/08/06 09:43:56  jschmalz
+ *	Extensions and changes for Yukon
+ *
+ *	Revision 1.19  2002/08/02 12:00:08  rschmidt
+ *	Added defines for YUKON sensors
+ *	Editorial changes
+ *
+ *	Revision 1.18  2001/08/16 12:44:33  afischer
+ *	LM80 sensor init values corrected
+ *
+ *	Revision 1.17  1999/11/22 13:55:25  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.16  1999/11/12 08:24:10  malthoff
+ *	Change voltage warning and error limits
+ *	(warning +-5%, error +-10%).
+ *
+ *	Revision 1.15  1999/09/14 14:14:43  malthoff
+ *	The 1000BT Dual Link adapter has got only one Fan.
+ *	The second Fan has been removed.
+ *
+ *	Revision 1.14  1999/05/27 13:40:50  malthoff
+ *	Fan Divisor = 1. Assuming fan with 6500 rpm.
+ *
+ *	Revision 1.13  1999/05/20 14:56:55  malthoff
+ *	Bug Fix: Missing brace in SK_LM80_FAN_FAKTOR.
+ *
+ *	Revision 1.12  1999/05/20 09:22:00  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *
+ *	Revision 1.11  1998/10/14 05:57:22  cgoos
+ *	Fixed compilation warnings.
+ *
+ *	Revision 1.10  1998/09/04 08:37:00  malthoff
+ *	bugfix: correct the SK_I2C_GET_CTL() macro.
+ *
+ *	Revision 1.9  1998/08/25 06:10:03  gklug
+ *	add: thresholds for all sensors
+ *
+ *	Revision 1.8  1998/08/20 11:37:42  gklug
+ *	chg: change Ioc to IoC
+ *
+ *	Revision 1.7  1998/08/20 08:53:11  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *
+ *	Revision 1.6  1998/08/17 11:37:09  malthoff
+ *	Bugfix in SK_I2C_CTL macro. The parameter 'dev'
+ *	has to be shifted 9 bits.
+ *
+ *	Revision 1.5  1998/08/17 06:52:21  malthoff
+ *	Remove unrequired macros.
+ *	Add macros for accessing TWSI SW register.
+ *
+ *	Revision 1.4  1998/08/13 08:30:18  gklug
+ *	add: conversion factors for read values
+ *	add: new state SEN_VALEXT to read extension value of temperature sensor
+ *
+ *	Revision 1.3  1998/08/12 13:37:56  gklug
+ *	rmv: error numbers and messages
+ *
+ *	Revision 1.2  1998/08/11 07:54:38  gklug
+ *	add: sensor states for GE sensors
+ *	add: Macro to access TWSI hardware register
+ *	chg: Error messages for TWSI errors
+ *
+ *	Revision 1.1  1998/07/17 11:27:56  gklug
+ *	Created.
+ *
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEI2C.H	contains all SK-98xx specific defines for the TWSI handling
+ */
+
+#ifndef _INC_SKGEI2C_H_
+#define _INC_SKGEI2C_H_
+
+/*
+ * Macros to access the B2_I2C_CTRL
+ */
+#define SK_I2C_CTL(IoC, flag, dev, reg, burst) \
+	SK_OUT32(IoC, B2_I2C_CTRL,\
+		(flag ? 0x80000000UL : 0x0L) | \
+		(((SK_U32) reg << 16) & I2C_ADDR) | \
+		(((SK_U32) dev << 9) & I2C_DEV_SEL) | \
+		(( burst << 4) & I2C_BURST_LEN))
+
+#define SK_I2C_STOP(IoC) {				\
+	SK_U32	I2cCtrl;				\
+	SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl);		\
+	SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP);	\
+}
+
+#define SK_I2C_GET_CTL(IoC, pI2cCtrl)	SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl)
+
+/*
+ * Macros to access the TWSI SW Registers
+ */
+#define SK_I2C_SET_BIT(IoC, SetBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits));	\
+}
+
+#define SK_I2C_CLR_BIT(IoC, ClrBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits)));	\
+}
+
+#define SK_I2C_GET_SW(IoC, pI2cSw)	SK_IN8(IoC, B2_I2C_SW, pI2cSw)
+
+/*
+ * define the possible sensor states
+ */
+#define	SK_SEN_IDLE		0	/* Idle: sensor not read */
+#define	SK_SEN_VALUE	1	/* Value Read cycle */
+#define	SK_SEN_VALEXT	2	/* Extended Value Read cycle */
+
+/*
+ * Conversion factor to convert read Voltage sensor to milli Volt
+ * Conversion factor to convert read Temperature sensor to 10th degree Celsius
+ */
+#define	SK_LM80_VT_LSB		22	/* 22mV LSB resolution */
+#define	SK_LM80_TEMP_LSB	10	/* 1 degree LSB resolution */
+#define	SK_LM80_TEMPEXT_LSB	5	/* 0.5 degree LSB resolution for the
+					 * extension value
+					 */
+#define SK_LM80_FAN_FAKTOR	((22500L*60)/(1*2))
+/* formula: counter = (22500*60)/(rpm * divisor * pulses/2)
+ * assuming: 6500rpm, 4 pulses, divisor 1
+ */
+
+/*
+ * Define sensor management data
+ * Maximum is reached on copperfield with dual Broadcom.
+ * Board specific maximum is in pAC->I2c.MaxSens
+ */
+#define	SK_MAX_SENSORS	8	/* maximal no. of installed sensors */
+#define	SK_MIN_SENSORS	5	/* minimal no. of installed sensors */
+
+/*
+ * To watch the statemachine (JS) use the timer in two ways instead of one as hitherto
+ */
+#define	SK_TIMER_WATCH_STATEMACHINE	0	/* Watch the statemachine to finish in a specific time */
+#define	SK_TIMER_NEW_GAUGING    	1	/* Start a new gauging when timer expires */
+
+
+/*
+ * Defines for the individual Thresholds
+ */
+
+/* Temperature sensor */
+#define	SK_SEN_TEMP_HIGH_ERR    800	/* Temperature High Err  Threshold */
+#define	SK_SEN_TEMP_HIGH_WARN	700	/* Temperature High Warn Threshold */
+#define	SK_SEN_TEMP_LOW_WARN	100	/* Temperature Low  Warn Threshold */
+#define	SK_SEN_TEMP_LOW_ERR       0	/* Temperature Low  Err  Threshold */
+
+/* VCC which should be 5 V */
+#define	SK_SEN_PCI_5V_HIGH_ERR  	5588	/* Voltage PCI High Err  Threshold */
+#define	SK_SEN_PCI_5V_HIGH_WARN     5346	/* Voltage PCI High Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_WARN		4664	/* Voltage PCI Low  Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_ERR		4422	/* Voltage PCI Low  Err  Threshold */
+
+/*
+ * VIO may be 5 V or 3.3 V. Initialization takes two parts:
+ * 1. Initialize lowest lower limit and highest higher limit.
+ * 2. After the first value is read correct the upper or the lower limit to
+ *    the appropriate C constant.
+ *
+ * Warning limits are +-5% of the exepected voltage.
+ * Error limits are +-10% of the expected voltage.
+ */
+
+/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */
+
+#define	SK_SEN_PCI_IO_5V_HIGH_ERR	5566	/* + 10% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_5V_HIGH_WARN	5324	/* +  5% V PCI-IO High Warn Threshold */
+					/*		5000	mVolt */
+#define	SK_SEN_PCI_IO_5V_LOW_WARN	4686	/* -  5% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_5V_LOW_ERR	4444	/* - 10% V PCI-IO Low Err Threshold */
+
+#define	SK_SEN_PCI_IO_RANGE_LIMITER	4000	/* 4000 mV range delimiter */
+
+/* correction values for the second pass */
+#define	SK_SEN_PCI_IO_3V3_HIGH_ERR	3850	/* + 15% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_3V3_HIGH_WARN	3674	/* + 10% V PCI-IO High Warn Threshold */
+					/*		3300	mVolt */
+#define	SK_SEN_PCI_IO_3V3_LOW_WARN  2926	/* - 10% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_3V3_LOW_ERR   2772	/* - 15% V PCI-IO Low Err  Threshold */
+
+
+/*
+ * VDD voltage
+ */
+#define	SK_SEN_VDD_HIGH_ERR	    3630	/* Voltage ASIC High Err  Threshold */
+#define	SK_SEN_VDD_HIGH_WARN    3476	/* Voltage ASIC High Warn Threshold */
+#define	SK_SEN_VDD_LOW_WARN     3146	/* Voltage ASIC Low  Warn Threshold */
+#define	SK_SEN_VDD_LOW_ERR      2970	/* Voltage ASIC Low  Err  Threshold */
+
+/*
+ * PHY PLL 3V3 voltage
+ */
+#define	SK_SEN_PLL_3V3_HIGH_ERR		3630	/* Voltage PMA High Err  Threshold */
+#define	SK_SEN_PLL_3V3_HIGH_WARN	3476	/* Voltage PMA High Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_WARN		3146	/* Voltage PMA Low  Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_ERR		2970	/* Voltage PMA Low  Err  Threshold */
+
+/*
+ * VAUX (YUKON only)
+ */
+#define	SK_SEN_VAUX_3V3_HIGH_ERR	3630	/* Voltage VAUX High Err Threshold */
+#define	SK_SEN_VAUX_3V3_HIGH_WARN	3476	/* Voltage VAUX High Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_WARN	3146	/* Voltage VAUX Low Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_ERR	    2970	/* Voltage VAUX Low Err Threshold */
+#define	SK_SEN_VAUX_0V_WARN_ERR	       0	/* if VAUX not present */
+#define	SK_SEN_VAUX_RANGE_LIMITER	1000	/* 1000 mV range delimiter */
+
+/*
+ * PHY 2V5 voltage
+ */
+#define	SK_SEN_PHY_2V5_HIGH_ERR		2750	/* Voltage PHY High Err Threshold */
+#define	SK_SEN_PHY_2V5_HIGH_WARN	2640	/* Voltage PHY High Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_WARN		2376	/* Voltage PHY Low Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_ERR		2222	/* Voltage PHY Low Err Threshold */
+
+/*
+ * ASIC Core 1V5 voltage (YUKON only)
+ */
+#define	SK_SEN_CORE_1V5_HIGH_ERR    1650	/* Voltage ASIC Core High Err Threshold */
+#define	SK_SEN_CORE_1V5_HIGH_WARN	1575	/* Voltage ASIC Core High Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_WARN	1425	/* Voltage ASIC Core Low Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_ERR 	1350	/* Voltage ASIC Core Low Err Threshold */
+
+/*
+ * FAN 1 speed
+ */
+/* assuming: 6500rpm +-15%, 4 pulses,
+ * warning at:	80 %
+ * error at:	70 %
+ * no upper limit
+ */
+#define	SK_SEN_FAN_HIGH_ERR		20000	/* FAN Speed High Err Threshold */
+#define	SK_SEN_FAN_HIGH_WARN	20000	/* FAN Speed High Warn Threshold */
+#define	SK_SEN_FAN_LOW_WARN 	5200	/* FAN Speed Low Warn Threshold */
+#define	SK_SEN_FAN_LOW_ERR		4550	/* FAN Speed Low Err Threshold */
+
+/*
+ * Some Voltages need dynamic thresholds
+ */
+#define	SK_SEN_DYN_INIT_NONE		 0  /* No dynamic init of thresholds */
+#define	SK_SEN_DYN_INIT_PCI_IO		10  /* Init PCI-IO with new thresholds */
+#define	SK_SEN_DYN_INIT_VAUX		11  /* Init VAUX with new thresholds */
+
+extern	int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#endif	/* n_INC_SKGEI2C_H */
diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h
new file mode 100644
index 0000000..cdddef9
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgeinit.h
@@ -0,0 +1,1113 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.75 $
+ * Date:	$Date: 2003/02/05 13:36:39 $
+ * Purpose:	Structures and prototypes for the GE Init Module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgeinit.h,v $
+ *	Revision 1.75  2003/02/05 13:36:39  rschmidt
+ *	Added define SK_FACT_78	for YUKON's Host Clock of 78.12 MHz
+ *	Editorial changes
+ *
+ *	Revision 1.74  2003/01/28 09:39:16  rschmidt
+ *	Added entry GIYukonLite in s_GeInit structure
+ *	Editorial changes
+ *
+ *	Revision 1.73  2002/11/15 12:47:25  rschmidt
+ *	Replaced error message SKERR_HWI_E024 for Cable Diagnostic with
+ *	Rx queue error in SkGeStopPort().
+ *
+ *	Revision 1.72  2002/11/12 17:08:35  rschmidt
+ *	Added entries for Cable Diagnostic to Port structure
+ *	Added entries GIPciSlot64 and GIPciClock66 in s_GeInit structure
+ *	Added error message for Cable Diagnostic
+ *	Added prototypes for SkGmCableDiagStatus()
+ *	Editorial changes
+ *
+ *	Revision 1.71  2002/10/21 11:26:10  mkarl
+ *	Changed interface of SkGeInitAssignRamToQueues().
+ *
+ *	Revision 1.70  2002/10/14 08:21:32  rschmidt
+ *	Changed type of GICopperType, GIVauxAvail to SK_BOOL
+ *	Added entry PRxOverCnt to Port structure
+ *	Added entry GIYukon32Bit in s_GeInit structure
+ *	Editorial changes
+ *
+ *	Revision 1.69  2002/10/09 16:57:15  mkarl
+ *	Added some constants and macros for SkGeInitAssignRamToQueues().
+ *
+ *	Revision 1.68  2002/09/12 08:58:51  rwahl
+ *	Retrieve counters needed for XMAC errata workarounds directly because
+ *	PNMI returns corrected counter values (e.g. #10620).
+ *
+ *	Revision 1.67  2002/08/16 14:40:30  rschmidt
+ *	Added entries GIGenesis and GICopperType in s_GeInit structure
+ *	Added prototypes for SkMacHashing()
+ *	Editorial changes
+ *
+ *	Revision 1.66  2002/08/12 13:27:21  rschmidt
+ *	Added defines for Link speed capabilities
+ *	Added entry PLinkSpeedCap to Port structure
+ *	Added entry GIVauxAvail in s_GeInit structure
+ *	Added prototypes for SkMacPromiscMode()
+ *	Editorial changes
+ *
+ *	Revision 1.65  2002/08/08 15:46:18  rschmidt
+ *	Added define SK_PHY_ACC_TO for PHY access timeout
+ *	Added define SK_XM_RX_HI_WM for XMAC Rx High Watermark
+ *	Added define SK_MIN_TXQ_SIZE for Min RAM Buffer Tx Queue Size
+ *	Added entry PhyId1 to Port structure
+ *
+ *	Revision 1.64  2002/07/23 16:02:56  rschmidt
+ *	Added entry GIWolOffs in s_GeInit struct (HW-Bug in YUKON 1st rev.)
+ *	Added prototypes for: SkGePhyRead(), SkGePhyWrite()
+ *
+ *	Revision 1.63  2002/07/18 08:17:38  rwahl
+ *	Corrected definitions for SK_LSPEED_xxx & SK_LSPEED_STAT_xxx.
+ *
+ *	Revision 1.62  2002/07/17 18:21:55  rwahl
+ *	Added SK_LSPEED_INDETERMINATED define.
+ *
+ *	Revision 1.61  2002/07/17 17:16:03  rwahl
+ *	- MacType now member of GIni struct.
+ *	- Struct alignment to 32bit.
+ *	- Editorial change.
+ *
+ *	Revision 1.60  2002/07/15 18:23:39  rwahl
+ *	Added GeMacFunc to GE Init structure.
+ *	Added prototypes for SkXmUpdateStats(), SkGmUpdateStats(),
+ *	  SkXmMacStatistic(), SkGmMacStatistic(), SkXmResetCounter(),
+ *	  SkGmResetCounter(), SkXmOverflowStatus(), SkGmOverflowStatus().
+ *	Added defines for current link speed state.
+ *	Added ERRMSG defintions for MacUpdateStat() & MacStatistics().
+ *
+ *	Revision 1.59  2002/07/15 15:40:22  rschmidt
+ *	Added entry PLinkSpeedUsed to Port structure
+ *	Editorial changes
+ *
+ *	Revision 1.58  2002/06/10 09:36:30  rschmidt
+ *	Editorial changes.
+ *
+ *	Revision 1.57  2002/06/05 08:18:00  rschmidt
+ *	Corrected alignment in Port Structure
+ *	Added new prototypes for GMAC
+ *	Editorial changes
+ *
+ *	Revision 1.56  2002/04/25 11:38:12  rschmidt
+ *	Added defines for Link speed values
+ *	Added defines for Loopback parameters for MAC and PHY
+ *	Removed entry PRxCmd from Port structure
+ *	Added entry PLinkSpeed to Port structure
+ *	Added entries GIChipId and GIChipRev to GE Init structure
+ *	Removed entry GIAnyPortAct from GE Init structure
+ *	Added prototypes for: SkMacInit(), SkMacInitPhy(),
+ *	SkMacRxTxDisable(), SkMacSoftRst(), SkMacHardRst(), SkMacIrq(),
+ *	SkMacIrqDisable(), SkMacFlushTxFifo(), SkMacFlushRxFifo(),
+ *	SkMacAutoNegDone(), SkMacAutoNegLipaPhy(), SkMacSetRxTxEn(),
+ *	SkXmPhyRead(), SkXmPhyRead(), SkGmPhyWrite(), SkGmPhyWrite();
+ *	Removed prototypes for static functions in SkXmac2.c
+ *	Editorial changes
+ *
+ *	Revision 1.55  2002/02/26 15:24:53  rwahl
+ *	Fix: no link with manual configuration (#10673). The previous fix for
+ *	#10639 was removed. So for RLMT mode = CLS the RLMT may switch to
+ *	misconfigured port. It should not occur for the other RLMT modes.
+ *
+ *	Revision 1.54  2002/01/18 16:52:52  rwahl
+ *	Editorial corrections.
+ *
+ *	Revision 1.53  2001/11/20 09:19:58  rwahl
+ *	Reworked bugfix #10639 (no dependency to RLMT mode).
+ *
+ *	Revision 1.52  2001/10/26 07:52:23  afischer
+ *	Port switching bug in `check local link` mode
+ *
+ *	Revision 1.51  2001/02/09 12:26:38  cgoos
+ *	Inserted #ifdef DIAG for half duplex workaround timer.
+ *
+ *	Revision 1.50  2001/02/07 07:56:40  rassmann
+ *	Corrected copyright.
+ *
+ *	Revision 1.49  2001/01/31 15:32:18  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *	add: counter for autoneg timeouts
+ *
+ *	Revision 1.48  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *
+ *	Revision 1.47  2000/10/18 12:22:40  cgoos
+ *	Added workaround for half duplex hangup.
+ *
+ *	Revision 1.46  2000/08/10 11:28:00  rassmann
+ *	Editorial changes.
+ *	Preserving 32-bit alignment in structs for the adapter context.
+ *
+ *	Revision 1.45  1999/11/22 13:56:19  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.44  1999/10/26 07:34:15  malthoff
+ *	The define SK_LNK_ON has been lost in v1.41.
+ *
+ *	Revision 1.43  1999/10/06 09:30:16  cgoos
+ *	Changed SK_XM_THR_JUMBO.
+ *
+ *	Revision 1.42  1999/09/16 12:58:26  cgoos
+ *	Changed SK_LED_STANDY macro to be independent of HW link sync.
+ *
+ *	Revision 1.41  1999/07/30 06:56:14  malthoff
+ *	Correct comment for SK_MS_STAT_UNSET.
+ *
+ *	Revision 1.40  1999/05/27 13:38:46  cgoos
+ *	Added SK_BMU_TX_WM.
+ *	Made SK_BMU_TX_WM and SK_BMU_RX_WM user-definable.
+ *	Changed XMAC Tx treshold to max. values.
+ *
+ *	Revision 1.39  1999/05/20 14:35:26  malthoff
+ *	Remove prototypes for SkGeLinkLED().
+ *
+ *	Revision 1.38  1999/05/19 11:59:12  cgoos
+ *	Added SK_MS_CAP_INDETERMINATED define.
+ *
+ *	Revision 1.37  1999/05/19 07:32:33  cgoos
+ *	Changes for 1000Base-T.
+ *	LED-defines for HWAC_LINK_LED macro.
+ *
+ *	Revision 1.36  1999/04/08 14:00:24  gklug
+ *	add:Port struct field PLinkResCt
+ *
+ *	Revision 1.35  1999/03/25 07:43:07  malthoff
+ *	Add error string for SKERR_HWI_E018MSG.
+ *
+ *	Revision 1.34  1999/03/12 16:25:57  malthoff
+ *	Remove PPollRxD and PPollTxD.
+ *	Add SKERR_HWI_E017MSG. and SK_DPOLL_MAX.
+ *
+ *	Revision 1.33  1999/03/12 13:34:41  malthoff
+ *	Add Autonegotiation error codes.
+ *	Change defines for parameter Mode in SkXmSetRxCmd().
+ *	Replace __STDC__ by SK_KR_PROTO.
+ *
+ *	Revision 1.32  1999/01/25 14:40:20  mhaveman
+ *	Added new return states for the virtual management port if multiple
+ *	ports are active but differently configured.
+ *
+ *	Revision 1.31  1998/12/11 15:17:02  gklug
+ *	add: Link partnet autoneg states : Unknown Manual and Auto-negotiation
+ *
+ *	Revision 1.30  1998/12/07 12:17:04  gklug
+ *	add: Link Partner auto-negotiation flag
+ *
+ *	Revision 1.29  1998/12/01 10:54:42  gklug
+ *	add: variables for XMAC Errata
+ *
+ *	Revision 1.28  1998/12/01 10:14:15  gklug
+ *	add: PIsave saves the Interrupt status word
+ *
+ *	Revision 1.27  1998/11/26 15:24:52  mhaveman
+ *	Added link status states SK_LMODE_STAT_AUTOHALF and
+ *	SK_LMODE_STAT_AUTOFULL which are used by PNMI.
+ *
+ *	Revision 1.26  1998/11/26 14:53:01  gklug
+ *	add:autoNeg Timeout variable
+ *
+ *	Revision 1.25  1998/11/26 08:58:50  gklug
+ *	add: Link Mode configuration (AUTO Sense mode)
+ *
+ *	Revision 1.24  1998/11/24 13:30:27  gklug
+ *	add: PCheckPar to port struct
+ *
+ *	Revision 1.23  1998/11/18 13:23:26  malthoff
+ *	Add SK_PKT_TO_MAX.
+ *
+ *	Revision 1.22  1998/11/18 13:19:54  gklug
+ *	add: PPrevShorts and PLinkBroken to port struct for WA XMAC Errata #C1
+ *
+ *	Revision 1.21  1998/10/26 08:02:57  malthoff
+ *	Add GIRamOffs.
+ *
+ *	Revision 1.20  1998/10/19 07:28:37  malthoff
+ *	Add prototype for SkGeInitRamIface().
+ *
+ *	Revision 1.19  1998/10/14 14:47:48  malthoff
+ *	SK_TIMER should not be defined for Diagnostics.
+ *	Add SKERR_HWI_E015MSG and SKERR_HWI_E016MSG.
+ *
+ *	Revision 1.18  1998/10/14 14:00:03  gklug
+ *	add: timer to port struct for workaround of Errata #2
+ *
+ *	Revision 1.17  1998/10/14 11:23:09  malthoff
+ *	Add prototype for SkXmAutoNegDone().
+ *	Fix SkXmSetRxCmd() prototype statement.
+ *
+ *	Revision 1.16  1998/10/14 05:42:29  gklug
+ *	add: HWLinkUp flag to Port struct
+ *
+ *	Revision 1.15  1998/10/09 08:26:33  malthoff
+ *	Rename SK_RB_ULPP_B to SK_RB_LLPP_B.
+ *
+ *	Revision 1.14  1998/10/09 07:11:13  malthoff
+ *	bug fix: SK_FACT_53 is 85 not 117.
+ *	Rework time out init values.
+ *	Add GIPortUsage and corresponding defines.
+ *	Add some error log messages.
+ *
+ *	Revision 1.13  1998/10/06 14:13:14  malthoff
+ *	Add prototype for SkGeLoadLnkSyncCnt().
+ *
+ *	Revision 1.12  1998/10/05 11:29:53  malthoff
+ *	bug fix: A comment was not closed.
+ *
+ *	Revision 1.11  1998/10/05 08:01:59  malthoff
+ *	Add default Timeout- Threshold- and
+ *	Watermark constants. Add QRam start and end
+ *	variables. Also add vars to store the polling
+ *	mode and receive command. Add new Error Log
+ *	Messages and function prototypes.
+ *
+ *	Revision 1.10  1998/09/28 13:34:48  malthoff
+ *	Add mode bits for LED functions.
+ *	Move Autoneg and Flow Ctrl bits from shgesirq.h
+ *	Add the required Error Log Entries
+ *	and Function Prototypes.
+ *
+ *	Revision 1.9  1998/09/16 14:38:41  malthoff
+ *	Rework the SK_LNK_xxx defines.
+ *	Add error log message defines.
+ *	Add prototypes for skxmac2.c
+ *
+ *	Revision 1.8  1998/09/11 05:29:18  gklug
+ *	add: init state of a port
+ *
+ *	Revision 1.7  1998/09/08 08:35:52  gklug
+ *	add: defines of the Init Levels
+ *
+ *	Revision 1.6  1998/09/03 13:48:42  gklug
+ *	add: Link strati, capabilities to Port struct
+ *
+ *	Revision 1.5  1998/09/03 13:30:59  malthoff
+ *	Add SK_LNK_BLINK and SK_LNK_PERM.
+ *
+ *	Revision 1.4  1998/09/03 09:55:31  malthoff
+ *	Add constants for parameters Dir and RstMode
+ *	when calling SkGeStopPort().
+ *	Rework the prototype section.
+ *	Add Queue Address offsets PRxQOff, PXsQOff, and PXaQOff.
+ *	Remove Ioc with IoC.
+ *
+ *	Revision 1.3  1998/08/19 09:11:54  gklug
+ *	fix: struct are removed from c-source (see CCC)
+ *	add: typedefs for all structs
+ *
+ *	Revision 1.2  1998/07/28 12:38:26  malthoff
+ *	The prototypes got the parameter 'IoC'.
+ *
+ *	Revision 1.1  1998/07/23 09:50:24  malthoff
+ *	Created.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEINIT_H_
+#define __INC_SKGEINIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/* modifying Link LED behaviour (used with SkGeLinkLED()) */
+#define SK_LNK_OFF		LED_OFF
+#define SK_LNK_ON		(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LNK_BLINK	(LED_ON | LED_BLK_ON  | LED_SYNC_ON)
+#define SK_LNK_PERM		(LED_ON | LED_BLK_OFF | LED_SYNC_ON)
+#define SK_LNK_TST		(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */
+#define SK_LED_OFF		LED_OFF
+#define SK_LED_ACTIVE	(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LED_STANDBY	(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* addressing LED Registers in SkGeXmitLED() */
+#define XMIT_LED_INI	0
+#define XMIT_LED_CNT	(RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL	(RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST	(RX_LED_TST - RX_LED_INI)
+
+/* parameter 'Mode' when calling SkGeXmitLED() */
+#define SK_LED_DIS	0
+#define SK_LED_ENA	1
+#define SK_LED_TST	2
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR		0x002faf08L		/*  50 ms */
+#define SK_BLK_DUR		0x01dcd650L		/* 500 ms */
+
+#define SK_DPOLL_DEF	0x00ee6b28L		/* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX	0x00ffffffL		/* 268 ms at 62.5 MHz */
+										/* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62		100			/* is given in percent */
+#define SK_FACT_53		 85         /* on GENESIS:	53.12 MHz */
+#define SK_FACT_78		125			/* on YUKON:	78.12 MHz */
+
+/* Timeout values */
+#define SK_MAC_TO_53	72			/* MAC arbiter timeout */
+#define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
+#define SK_PKT_TO_MAX	0xffff		/* Maximum value */
+#define SK_RI_TO_53		36			/* RAM interface timeout */
+
+#define SK_PHY_ACC_TO	600000		/* PHY access timeout */
+
+/* RAM Buffer High Pause Threshold values */
+#define SK_RB_ULPP		( 8 * 1024)	/* Upper Level in kB/8 */
+#define SK_RB_LLPP_S	(10 * 1024)	/* Lower Level for small Queues */
+#define SK_RB_LLPP_B	(16 * 1024)	/* Lower Level for big Queues */
+
+#ifndef SK_BMU_RX_WM
+#define SK_BMU_RX_WM	0x600		/* BMU Rx Watermark */
+#endif
+#ifndef SK_BMU_TX_WM
+#define SK_BMU_TX_WM	0x600		/* BMU Tx Watermark */
+#endif
+
+/* XMAC II Rx High Watermark */
+#define SK_XM_RX_HI_WM	0x05aa		/* 1450 */
+
+/* XMAC II Tx Threshold */
+#define SK_XM_THR_REDL	0x01fb		/* .. for redundant link usage */
+#define SK_XM_THR_SL	0x01fb		/* .. for single link adapters */
+#define SK_XM_THR_MULL	0x01fb		/* .. for multiple link usage */
+#define SK_XM_THR_JUMBO	0x03fc		/* .. for jumbo frame usage */
+
+/* values for GIPortUsage */
+#define SK_RED_LINK		1		/* redundant link usage */
+#define SK_MUL_LINK		2		/* multiple link usage */
+#define SK_JUMBO_LINK	3		/* driver uses jumbo frames */
+
+/* Minimum RAM Buffer Rx Queue Size */
+#define SK_MIN_RXQ_SIZE	16		/* 16 kB */
+
+/* Minimum RAM Buffer Tx Queue Size */
+#define SK_MIN_TXQ_SIZE	16		/* 16 kB */
+
+/* Queue Size units */
+#define QZ_UNITS		0x7
+#define QZ_STEP			8
+
+/* Percentage of queue size from whole memory */
+/* 80 % for receive */
+#define RAM_QUOTA_RX	80L
+/* 0% for sync transfer */
+#define	RAM_QUOTA_SYNC	0L
+/* the rest (20%) is taken for async transfer */
+
+/* Get the rounded queue size in Bytes in 8k steps */
+#define ROUND_QUEUE_SIZE(SizeInBytes)					\
+	((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) &	\
+	~(QZ_STEP-1))
+
+/* Get the rounded queue size in KBytes in 8k steps */
+#define ROUND_QUEUE_SIZE_KB(Kilobytes) \
+	ROUND_QUEUE_SIZE((Kilobytes) * 1024L)
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q	1	/* small receive queue */
+#define SK_RX_BRAM_Q	2	/* big receive queue */
+#define SK_TX_RAM_Q		3	/* small or big transmit queue */
+
+/* parameter 'Dir' when calling SkGeStopPort() */
+#define SK_STOP_TX	1	/* Stops the transmit path, resets the XMAC */
+#define SK_STOP_RX	2	/* Stops the receive path */
+#define SK_STOP_ALL	3	/* Stops Rx and Tx path, resets the XMAC */
+
+/* parameter 'RstMode' when calling SkGeStopPort() */
+#define SK_SOFT_RST	1	/* perform a software reset */
+#define SK_HARD_RST	2	/* perform a hardware reset */
+
+/* Init Levels */
+#define SK_INIT_DATA	0	/* Init level 0: init data structures */
+#define SK_INIT_IO		1	/* Init level 1: init with IOs */
+#define SK_INIT_RUN		2	/* Init level 2: init for run time */
+
+/* Link Mode Parameter */
+#define SK_LMODE_HALF		1	/* Half Duplex Mode */
+#define SK_LMODE_FULL		2	/* Full Duplex Mode */
+#define SK_LMODE_AUTOHALF	3	/* AutoHalf Duplex Mode */
+#define SK_LMODE_AUTOFULL	4	/* AutoFull Duplex Mode */
+#define SK_LMODE_AUTOBOTH	5	/* AutoBoth Duplex Mode */
+#define SK_LMODE_AUTOSENSE	6	/* configured mode auto sensing */
+#define SK_LMODE_INDETERMINATED	7	/* indeterminated */
+
+/* Auto-negotiation timeout in 100ms granularity */
+#define SK_AND_MAX_TO		6	/* Wait 600 msec before link comes up */
+
+/* Auto-negotiation error codes */
+#define SK_AND_OK			0	/* no error */
+#define SK_AND_OTHER		1	/* other error than below */
+#define SK_AND_DUP_CAP		2	/* Duplex capabilities error */
+
+
+/* Link Speed Capabilities */
+#define SK_LSPEED_CAP_AUTO			(1<<0)	/* Automatic resolution */
+#define SK_LSPEED_CAP_10MBPS		(1<<1)	/* 10 Mbps */
+#define SK_LSPEED_CAP_100MBPS		(1<<2)	/* 100 Mbps */
+#define SK_LSPEED_CAP_1000MBPS		(1<<3)	/* 1000 Mbps */
+#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Speed Parameter */
+#define SK_LSPEED_AUTO				1	/* Automatic resolution */
+#define SK_LSPEED_10MBPS			2	/* 10 Mbps */
+#define SK_LSPEED_100MBPS			3	/* 100 Mbps */
+#define SK_LSPEED_1000MBPS			4	/* 1000 Mbps */
+#define SK_LSPEED_INDETERMINATED	5	/* indeterminated */
+
+/* Link Speed Current State */
+#define SK_LSPEED_STAT_UNKNOWN		1
+#define SK_LSPEED_STAT_10MBPS		2
+#define SK_LSPEED_STAT_100MBPS 		3
+#define SK_LSPEED_STAT_1000MBPS		4
+#define SK_LSPEED_STAT_INDETERMINATED 5
+
+
+/* Link Capability Parameter */
+#define SK_LMODE_CAP_HALF		(1<<0)	/* Half Duplex Mode */
+#define SK_LMODE_CAP_FULL		(1<<1)	/* Full Duplex Mode */
+#define SK_LMODE_CAP_AUTOHALF	(1<<2)	/* AutoHalf Duplex Mode */
+#define SK_LMODE_CAP_AUTOFULL	(1<<3)	/* AutoFull Duplex Mode */
+#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Mode Current State */
+#define SK_LMODE_STAT_UNKNOWN	1	/* Unknown Duplex Mode */
+#define SK_LMODE_STAT_HALF		2	/* Half Duplex Mode */
+#define SK_LMODE_STAT_FULL		3	/* Full Duplex Mode */
+#define SK_LMODE_STAT_AUTOHALF	4	/* Half Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_AUTOFULL	5	/* Full Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_INDETERMINATED 6	/* indeterminated */
+
+/* Flow Control Mode Parameter (and capabilities) */
+#define SK_FLOW_MODE_NONE		1	/* No Flow-Control */
+#define SK_FLOW_MODE_LOC_SEND	2	/* Local station sends PAUSE */
+#define SK_FLOW_MODE_SYMMETRIC	3	/* Both stations may send PAUSE */
+#define SK_FLOW_MODE_SYM_OR_REM	4	/* Both stations may send PAUSE or
+					 * just the remote station may send PAUSE
+					 */
+#define SK_FLOW_MODE_INDETERMINATED 5	/* indeterminated */
+
+/* Flow Control Status Parameter */
+#define SK_FLOW_STAT_NONE		1	/* No Flow Control */
+#define SK_FLOW_STAT_REM_SEND	2	/* Remote Station sends PAUSE */
+#define SK_FLOW_STAT_LOC_SEND	3	/* Local station sends PAUSE */
+#define SK_FLOW_STAT_SYMMETRIC	4	/* Both station may send PAUSE */
+#define SK_FLOW_STAT_INDETERMINATED 5	/* indeterminated */
+
+/* Master/Slave Mode Capabilities */
+#define SK_MS_CAP_AUTO		(1<<0)	/* Automatic resolution */
+#define SK_MS_CAP_MASTER	(1<<1)	/* This station is master */
+#define SK_MS_CAP_SLAVE		(1<<2)	/* This station is slave */
+#define SK_MS_CAP_INDETERMINATED (1<<3)	/* indeterminated */
+
+/* Set Master/Slave Mode Parameter (and capabilities) */
+#define SK_MS_MODE_AUTO		1	/* Automatic resolution */
+#define SK_MS_MODE_MASTER	2	/* This station is master */
+#define SK_MS_MODE_SLAVE	3	/* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4	/* indeterminated */
+
+/* Master/Slave Status Parameter */
+#define SK_MS_STAT_UNSET	1	/* The M/S status is not set */
+#define SK_MS_STAT_MASTER	2	/* This station is Master */
+#define SK_MS_STAT_SLAVE	3	/* This station is Dlave */
+#define SK_MS_STAT_FAULT	4	/* M/S resolution failed */
+#define SK_MS_STAT_INDETERMINATED 5	/* indeterminated */
+
+/* parameter 'Mode' when calling SkXmSetRxCmd() */
+#define SK_STRIP_FCS_ON		(1<<0)	/* Enable  FCS stripping of Rx frames */
+#define SK_STRIP_FCS_OFF	(1<<1)	/* Disable FCS stripping of Rx frames */
+#define SK_STRIP_PAD_ON		(1<<2)	/* Enable  pad byte stripping of Rx fr */
+#define SK_STRIP_PAD_OFF	(1<<3)	/* Disable pad byte stripping of Rx fr */
+#define SK_LENERR_OK_ON		(1<<4)	/* Don't chk fr for in range len error */
+#define SK_LENERR_OK_OFF	(1<<5)	/* Check frames for in range len error */
+#define SK_BIG_PK_OK_ON		(1<<6)	/* Don't set Rx Error bit for big frames */
+#define SK_BIG_PK_OK_OFF	(1<<7)	/* Set Rx Error bit for big frames */
+#define SK_SELF_RX_ON		(1<<8)	/* Enable  Rx of own packets */
+#define SK_SELF_RX_OFF		(1<<9)	/* Disable Rx of own packets */
+
+/* parameter 'Para' when calling SkMacSetRxTxEn() */
+#define SK_MAC_LOOPB_ON		(1<<0)	/* Enable  MAC Loopback Mode */
+#define SK_MAC_LOOPB_OFF	(1<<1)	/* Disable MAC Loopback Mode */
+#define SK_PHY_LOOPB_ON		(1<<2)	/* Enable  PHY Loopback Mode */
+#define SK_PHY_LOOPB_OFF	(1<<3)	/* Disable PHY Loopback Mode */
+#define SK_PHY_FULLD_ON		(1<<4)	/* Enable  GMII Full Duplex */
+#define SK_PHY_FULLD_OFF	(1<<5)	/* Disable GMII Full Duplex */
+
+/* States of PState */
+#define SK_PRT_RESET	0	/* the port is reset */
+#define SK_PRT_STOP		1	/* the port is stopped (similar to SW reset) */
+#define SK_PRT_INIT		2	/* the port is initialized */
+#define SK_PRT_RUN		3	/* the port has an active link */
+
+/* Default receive frame limit for Workaround of XMAC Errata */
+#define SK_DEF_RX_WA_LIM	SK_CONSTU64(100)
+
+/* Link Partner Status */
+#define SK_LIPA_UNKNOWN	0	/* Link partner is in unknown state */
+#define SK_LIPA_MANUAL	1	/* Link partner is in detected manual state */
+#define SK_LIPA_AUTO	2	/* Link partner is in auto-negotiation state */
+
+/* Maximum Restarts before restart is ignored (3Com WA) */
+#define SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
+
+/* Max. Auto-neg. timeouts before link detection in sense mode is reset */
+#define SK_MAX_ANEG_TO	10	/* Max. 10 times the sense mode is reset */
+
+/* structures *****************************************************************/
+
+/*
+ * MAC specific functions
+ */
+typedef struct s_GeMacFunc {
+	int  (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+							SK_U16 StatAddr, SK_U32 *pVal);
+	int  (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+						   SK_U16 IStatus, SK_U64 *pVal);
+} SK_GEMACFUNC;
+
+/*
+ * Port Structure
+ */
+typedef	struct s_GePort {
+#ifndef SK_DIAG
+	SK_TIMER	PWaTimer;	/* Workaround Timer */
+	SK_TIMER	HalfDupChkTimer;
+#endif /* SK_DIAG */
+	SK_U32	PPrevShorts;	/* Previous short Counter checking */
+	SK_U32	PPrevFcs;		/* Previous FCS Error Counter checking */
+	SK_U64	PPrevRx;		/* Previous RxOk Counter checking */
+	SK_U64	PRxLim;			/* Previous RxOk Counter checking */
+	SK_U64	LastOctets;		/* For half duplex hang check */
+	int		PLinkResCt;		/* Link Restart Counter */
+	int		PAutoNegTimeOut;/* Auto-negotiation timeout current value */
+	int		PAutoNegTOCt;	/* Auto-negotiation Timeout Counter */
+	int		PRxQSize;		/* Port Rx Queue Size in kB */
+	int		PXSQSize;		/* Port Synchronous  Transmit Queue Size in kB */
+	int		PXAQSize;		/* Port Asynchronous Transmit Queue Size in kB */
+	SK_U32	PRxQRamStart;	/* Receive Queue RAM Buffer Start Address */
+	SK_U32	PRxQRamEnd;		/* Receive Queue RAM Buffer End Address */
+	SK_U32	PXsQRamStart;	/* Sync Tx Queue RAM Buffer Start Address */
+	SK_U32	PXsQRamEnd;		/* Sync Tx Queue RAM Buffer End Address */
+	SK_U32	PXaQRamStart;	/* Async Tx Queue RAM Buffer Start Address */
+	SK_U32	PXaQRamEnd;		/* Async Tx Queue RAM Buffer End Address */
+	SK_U32	PRxOverCnt;		/* Receive Overflow Counter */
+	int		PRxQOff;		/* Rx Queue Address Offset */
+	int		PXsQOff;		/* Synchronous Tx Queue Address Offset */
+	int		PXaQOff;		/* Asynchronous Tx Queue Address Offset */
+	int		PhyType;		/* PHY used on this port */
+	SK_U16	PhyId1;			/* PHY Id1 on this port */
+	SK_U16	PhyAddr;		/* MDIO/MDC PHY address */
+	SK_U16	PIsave;			/* Saved Interrupt status word */
+	SK_U16	PSsave;			/* Saved PHY status word */
+	SK_BOOL	PHWLinkUp;		/* The hardware Link is up (wiring) */
+	SK_BOOL	PState;			/* Is port initialized ? */
+	SK_BOOL	PLinkBroken;	/* Is Link broken ? */
+	SK_BOOL	PCheckPar;		/* Do we check for parity errors ? */
+	SK_BOOL	HalfDupTimerActive;
+	SK_U8	PLinkCap;		/* Link Capabilities */
+	SK_U8	PLinkModeConf;	/* Link Mode configured */
+	SK_U8	PLinkMode;		/* Link Mode currently used */
+	SK_U8	PLinkModeStatus;/* Link Mode Status */
+	SK_U8	PLinkSpeedCap;	/* Link Speed Capabilities(10/100/1000 Mbps) */
+	SK_U8	PLinkSpeed;		/* configured Link Speed (10/100/1000 Mbps) */
+	SK_U8	PLinkSpeedUsed;	/* current Link Speed (10/100/1000 Mbps) */
+	SK_U8	PFlowCtrlCap;	/* Flow Control Capabilities */
+	SK_U8	PFlowCtrlMode;	/* Flow Control Mode */
+	SK_U8	PFlowCtrlStatus;/* Flow Control Status */
+	SK_U8	PMSCap;			/* Master/Slave Capabilities */
+	SK_U8	PMSMode;		/* Master/Slave Mode */
+	SK_U8	PMSStatus;		/* Master/Slave Status */
+	SK_U8	PAutoNegFail;	/* Auto-negotiation fail flag */
+	SK_U8	PLipaAutoNeg;	/* Auto-negotiation possible with Link Partner */
+	SK_U8	PCableLen;		/* Cable Length */
+	SK_U8	PMdiPairLen[4];	/* MDI[0..3] Pair Length */
+	SK_U8	PMdiPairSts[4];	/* MDI[0..3] Pair Diagnostic Status */
+} SK_GEPORT;
+
+/*
+ * Gigabit Ethernet Initialization Struct
+ * (has to be included in the adapter context)
+ */
+typedef	struct s_GeInit {
+	SK_U8		GIPciHwRev;		/* PCI HW Revision Number */
+	SK_U8		GIChipId;		/* Chip Identification Number */
+	SK_U8		GIChipRev;		/* Chip Revision Number */
+	SK_BOOL		GIGenesis;		/* Genesis adapter ? */
+	SK_BOOL		GICopperType;	/* Copper Type adapter ? */
+	SK_BOOL		GIPciSlot64;	/* 64-bit PCI Slot */
+	SK_BOOL		GIPciClock66;	/* 66 MHz PCI Clock */
+	SK_BOOL		GIVauxAvail;	/* VAUX available (YUKON) */
+	SK_BOOL		GIYukon32Bit;	/* 32-Bit YUKON adapter */
+	SK_BOOL		GIYukonLite;	/* YUKON-Lite chip */
+	int			GIMacsFound;	/* Number of MACs found on this adapter */
+	int			GIMacType;		/* MAC Type used on this adapter */
+	int			GIHstClkFact;	/* Host Clock Factor (62.5 / HstClk * 100) */
+	int			GIPortUsage;	/* Driver Port Usage */
+	int			GILevel;		/* Initialization Level completed */
+	int			GIRamSize;		/* The RAM size of the adapter in kB */
+	int			GIWolOffs;		/* WOL Register Offset (HW-Bug in Rev. A) */
+	SK_U32		GIRamOffs;		/* RAM Address Offset for addr calculation */
+	SK_U32		GIPollTimerVal;	/* Descr. Poll Timer Init Val (HstClk ticks) */
+	SK_GEPORT	GP[SK_MAX_MACS];/* Port Dependent Information */
+	SK_GEMACFUNC GIFunc;		/* MAC depedent functions */
+} SK_GEINIT;
+
+/*
+ * Error numbers and messages for skxmac2.c and skgeinit.c
+ */
+#define SKERR_HWI_E001		(SK_ERRBASE_HWINIT)
+#define SKERR_HWI_E001MSG	"SkXmClrExactAddr() has got illegal parameters"
+#define SKERR_HWI_E002		(SKERR_HWI_E001+1)
+#define SKERR_HWI_E002MSG	"SkGeInit(): Level 1 call missing"
+#define SKERR_HWI_E003		(SKERR_HWI_E002+1)
+#define SKERR_HWI_E003MSG	"SkGeInit() called with illegal init Level"
+#define SKERR_HWI_E004		(SKERR_HWI_E003+1)
+#define SKERR_HWI_E004MSG	"SkGeInitPort(): Queue Size illegal configured"
+#define SKERR_HWI_E005		(SKERR_HWI_E004+1)
+#define SKERR_HWI_E005MSG	"SkGeInitPort(): cannot init running ports"
+#define SKERR_HWI_E006		(SKERR_HWI_E005+1)
+#define SKERR_HWI_E006MSG	"SkGeMacInit(): PState does not match HW state"
+#define SKERR_HWI_E007		(SKERR_HWI_E006+1)
+#define SKERR_HWI_E007MSG	"SkXmInitDupMd() called with invalid Dup Mode"
+#define SKERR_HWI_E008		(SKERR_HWI_E007+1)
+#define SKERR_HWI_E008MSG	"SkXmSetRxCmd() called with invalid Mode"
+#define SKERR_HWI_E009		(SKERR_HWI_E008+1)
+#define SKERR_HWI_E009MSG	"SkGeCfgSync() called although PXSQSize zero"
+#define SKERR_HWI_E010		(SKERR_HWI_E009+1)
+#define SKERR_HWI_E010MSG	"SkGeCfgSync() called with invalid parameters"
+#define SKERR_HWI_E011		(SKERR_HWI_E010+1)
+#define SKERR_HWI_E011MSG	"SkGeInitPort(): Receive Queue Size too small"
+#define SKERR_HWI_E012		(SKERR_HWI_E011+1)
+#define SKERR_HWI_E012MSG	"SkGeInitPort(): invalid Queue Size specified"
+#define SKERR_HWI_E013		(SKERR_HWI_E012+1)
+#define SKERR_HWI_E013MSG	"SkGeInitPort(): cfg changed for running queue"
+#define SKERR_HWI_E014		(SKERR_HWI_E013+1)
+#define SKERR_HWI_E014MSG	"SkGeInitPort(): unknown GIPortUsage specified"
+#define SKERR_HWI_E015		(SKERR_HWI_E014+1)
+#define SKERR_HWI_E015MSG	"Illegal Link mode parameter"
+#define SKERR_HWI_E016		(SKERR_HWI_E015+1)
+#define SKERR_HWI_E016MSG	"Illegal Flow control mode parameter"
+#define SKERR_HWI_E017		(SKERR_HWI_E016+1)
+#define SKERR_HWI_E017MSG	"Illegal value specified for GIPollTimerVal"
+#define SKERR_HWI_E018		(SKERR_HWI_E017+1)
+#define SKERR_HWI_E018MSG	"FATAL: SkGeStopPort() does not terminate (Tx)"
+#define SKERR_HWI_E019		(SKERR_HWI_E018+1)
+#define SKERR_HWI_E019MSG	"Illegal Speed parameter"
+#define SKERR_HWI_E020		(SKERR_HWI_E019+1)
+#define SKERR_HWI_E020MSG	"Illegal Master/Slave parameter"
+#define SKERR_HWI_E021		(SKERR_HWI_E020+1)
+#define	SKERR_HWI_E021MSG	"MacUpdateStats(): cannot update statistic counter"
+#define	SKERR_HWI_E022		(SKERR_HWI_E021+1)
+#define	SKERR_HWI_E022MSG	"MacStatistic(): illegal statistic base address"
+#define SKERR_HWI_E023		(SKERR_HWI_E022+1)
+#define SKERR_HWI_E023MSG	"SkGeInitPort(): Transmit Queue Size too small"
+#define SKERR_HWI_E024		(SKERR_HWI_E023+1)
+#define SKERR_HWI_E024MSG	"FATAL: SkGeStopPort() does not terminate (Rx)"
+#define SKERR_HWI_E025		(SKERR_HWI_E024+1)
+#define SKERR_HWI_E025MSG	""
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollRxD(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	PollRxD);
+
+extern void	SkGePollTxD(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL PollTxD);
+
+extern void	SkGeYellowLED(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		State);
+
+extern int	SkGeCfgSync(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U32	IntTime,
+	SK_U32	LimCount,
+	int		SyncMode);
+
+extern void	SkGeLoadLnkSyncCnt(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U32	CntVal);
+
+extern void	SkGeStopPort(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Dir,
+	int		RstMode);
+
+extern int	SkGeInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Level);
+
+extern void	SkGeDeInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+
+extern int	SkGeInitPort(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkGeXmitLED(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Led,
+	int		Mode);
+
+extern void	SkGeInitRamIface(
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+
+extern int	SkGeInitAssignRamToQueues(
+	SK_AC	*pAC,
+	int		ActivePort,
+	SK_BOOL	DualNet);
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacSoftRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacHardRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkXmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkGmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void SkMacInitPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	DoLoop);
+
+extern void SkMacIrqDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacFlushTxFifo(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacFlushRxFifo(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacIrq(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern int	SkMacAutoNegDone(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacAutoNegLipaPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U16	IStatus);
+
+extern void  SkMacSetRxTxEn(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Para);
+
+extern int  SkMacRxTxEnable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacPromiscMode(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkMacHashing(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkXmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkXmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkGmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkGmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkGePhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkGePhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkXmClrExactAddr(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		StartNum,
+	int		StopNum);
+
+extern void	SkXmInitDupMd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkXmInitPauseMd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkXmAutoNegLipaXmac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U16	IStatus);
+
+extern int SkXmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	*pVal);
+
+extern int SkGmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	*pVal);
+
+extern int SkXmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16  IStatus,
+	SK_U64	*pStatus);
+
+extern int SkGmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	MacStatus,
+	SK_U64	*pStatus);
+
+extern int SkGmCableDiagStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	StartTest);
+
+#ifdef SK_DIAG
+extern void	SkMacSetRxCmd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Mode);
+extern void	SkMacCrcGener(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+extern void	SkMacTimeStamp(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+extern void	SkXmSendCont(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+#endif /* SK_DIAG */
+
+#else	/* SK_KR_PROTO */
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollRxD();
+extern void	SkGePollTxD();
+extern void	SkGeYellowLED();
+extern int	SkGeCfgSync();
+extern void	SkGeLoadLnkSyncCnt();
+extern void	SkGeStopPort();
+extern int	SkGeInit();
+extern void	SkGeDeInit();
+extern int	SkGeInitPort();
+extern void	SkGeXmitLED();
+extern void	SkGeInitRamIface();
+extern int	SkGeInitAssignRamToQueues();
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable();
+extern void	SkMacSoftRst();
+extern void	SkMacHardRst();
+extern void SkMacInitPhy();
+extern int  SkMacRxTxEnable();
+extern void SkMacPromiscMode();
+extern void SkMacHashing();
+extern void SkMacIrqDisable();
+extern void	SkMacFlushTxFifo();
+extern void	SkMacFlushRxFifo();
+extern void	SkMacIrq();
+extern int	SkMacAutoNegDone();
+extern void	SkMacAutoNegLipaPhy();
+extern void SkMacSetRxTxEn();
+extern void	SkGePhyRead();
+extern void	SkGePhyWrite();
+extern void	SkXmInitMac();
+extern void	SkXmPhyRead();
+extern void	SkXmPhyWrite();
+extern void	SkGmInitMac();
+extern void	SkGmPhyRead();
+extern void	SkGmPhyWrite();
+extern void	SkXmClrExactAddr();
+extern void	SkXmInitDupMd();
+extern void	SkXmInitPauseMd();
+extern void	SkXmAutoNegLipaXmac();
+extern int	SkXmUpdateStats();
+extern int	SkGmUpdateStats();
+extern int	SkXmMacStatistic();
+extern int	SkGmMacStatistic();
+extern int	SkXmResetCounter();
+extern int	SkGmResetCounter();
+extern int	SkXmOverflowStatus();
+extern int	SkGmOverflowStatus();
+extern int	SkGmCableDiagStatus();
+
+#ifdef SK_DIAG
+extern void	SkMacSetRxCmd();
+extern void	SkMacCrcGener();
+extern void	SkMacTimeStamp();
+extern void	SkXmSendCont();
+#endif /* SK_DIAG */
+
+#endif	/* SK_KR_PROTO */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEINIT_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnm2.h b/drivers/net/sk98lin/h/skgepnm2.h
new file mode 100644
index 0000000..5c44f47
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnm2.h
@@ -0,0 +1,462 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnm2.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.34 $
+ * Date:	$Date: 2002/12/16 09:05:18 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnm2.h,v $
+ *	Revision 1.34  2002/12/16 09:05:18  tschilli
+ *	Code for VCT handling added.
+ *
+ *	Revision 1.33  2002/09/10 09:00:03  rwahl
+ *	Adapted boolean definitions according sktypes.
+ *
+ *	Revision 1.32  2002/08/09 09:47:01  rwahl
+ *	Added write-only flag to oid access defines.
+ *	Editorial changes.
+ *
+ *	Revision 1.31  2002/07/17 19:23:18  rwahl
+ *	- Replaced MAC counter definitions by enumeration.
+ *	- Added definition SK_PNMI_MAC_TYPES.
+ *	- Added chipset defnition for Yukon.
+ *
+ *	Revision 1.30  2001/02/06 10:03:41  mkunz
+ *	- Pnmi V4 dual net support added. Interface functions and macros extended
+ *	- Vpd bug fixed
+ *	- OID_SKGE_MTU added
+ *
+ *	Revision 1.29  2001/01/22 13:41:37  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.28  2000/08/03 15:12:48  rwahl
+ *	- Additional comment for MAC statistic data structure.
+ *
+ *	Revision 1.27  2000/08/01 16:10:18  rwahl
+ *	- Added mac statistic data structure for StatRxLongFrame counter.
+ *
+ *	Revision 1.26  2000/03/31 13:51:34  rwahl
+ *	Added SK_UPTR cast to offset calculation for PNMI struct fields;
+ *	missing cast caused compiler warnings by Win64 compiler.
+ *
+ *	Revision 1.25  1999/11/22 13:57:41  cgoos
+ *	Changed license header to GPL.
+ *	Allowing overwrite for SK_PNMI_STORE/_READ defines.
+ *
+ *	Revision 1.24  1999/04/13 15:11:11  mhaveman
+ *	Changed copyright.
+ *
+ *	Revision 1.23  1999/01/28 15:07:12  mhaveman
+ *	Changed default threshold for port switches per hour from 10
+ *	to 240 which means 4 switches per minute. This fits better
+ *	the granularity of 32 for the port switch estimate
+ *	counter.
+ *
+ *	Revision 1.22  1999/01/05 12:52:30  mhaveman
+ *	Removed macro SK_PNMI_MICRO_SEC.
+ *
+ *	Revision 1.21  1999/01/05 12:50:34  mhaveman
+ *	Enlarged macro definition SK_PNMI_HUNDREDS_SEC() so that no 64-bit
+ *	arithmetic is necessary if SK_TICKS_PER_SEC is 100.
+ *
+ *	Revision 1.20  1998/12/09 14:02:53  mhaveman
+ *	Defined macro SK_PNMI_DEF_RLMT_CHG_THRES for default port switch
+ *	threshold.
+ *
+ *	Revision 1.19  1998/12/03 11:28:41  mhaveman
+ *	Removed SK_PNMI_CHECKPTR macro.
+ *
+ *	Revision 1.18  1998/12/03 11:21:00  mhaveman
+ *	-Added pointer check macro SK_PNMI_CHECKPTR
+ *	-Added macros SK_PNMI_VPD_ARR_SIZE and SK_PNMI_VPD_STR_SIZE for
+ *	 VPD key evaluation.
+ *
+ *	Revision 1.17  1998/11/20 13:20:33  mhaveman
+ *	Fixed bug in SK_PNMI_SET_STAT macro. ErrorStatus was not correctly set.
+ *
+ *	Revision 1.16  1998/11/20 08:08:49  mhaveman
+ *	Macro SK_PNMI_CHECKFLAGS has got a if clause.
+ *
+ *	Revision 1.15  1998/11/03 13:53:40  mhaveman
+ *	Fixed alignment problem in macor SK_PNMI_SET_STAT macro.
+ *
+ *	Revision 1.14  1998/10/30 15:50:13  mhaveman
+ *	Added macro SK_PNMI_MICRO_SEC()
+ *
+ *	Revision 1.13  1998/10/30 12:32:20  mhaveman
+ *	Added forgotten cast in SK_PNMI_READ_U32 macro.
+ *
+ *	Revision 1.12  1998/10/29 15:40:26  mhaveman
+ *	-Changed SK_PNMI_TRAP_SENSOR_LEN because SensorDescr has now
+ *	 variable string length.
+ *	-Defined SK_PNMI_CHECKFLAGS macro
+ *
+ *	Revision 1.11  1998/10/29 08:53:34  mhaveman
+ *	Removed SK_PNMI_RLM_XXX table indexed because these counters need
+ *	not been saved over XMAC resets.
+ *
+ *	Revision 1.10  1998/10/28 08:48:20  mhaveman
+ *	-Added macros for storage according to alignment
+ *	-Changed type of Instance to SK_U32 because of VPD
+ *	-Removed trap structures. Not needed because of alignment problem
+ *	-Changed type of Action form SK_U8 to int
+ *
+ *	Revision 1.9  1998/10/21 13:34:45  mhaveman
+ *	Shit, mismatched calculation of SK_PNMI_HUNDREDS_SEC. Corrected.
+ *
+ *	Revision 1.8  1998/10/21 13:24:58  mhaveman
+ *	Changed calculation of hundreds of seconds.
+ *
+ *	Revision 1.7  1998/10/20 07:31:41  mhaveman
+ *	Made type changes to unsigned int where possible.
+ *
+ *	Revision 1.6  1998/09/04 17:04:05  mhaveman
+ *	Added Sync counters to offset storage to provided settled values on
+ *	port switch.
+ *
+ *	Revision 1.5  1998/09/04 12:45:35  mhaveman
+ *	Removed dummies for SK_DRIVER_ macros. They should be added by driver
+ *	writer in skdrv2nd.h.
+ *
+ *	Revision 1.4  1998/09/04 11:59:50  mhaveman
+ *	Everything compiles now. Driver Macros for counting still missing.
+ *
+ *	Revision 1.3  1998/08/24 12:01:35  mhaveman
+ *	Intermediate state.
+ *
+ *	Revision 1.2  1998/08/17 07:51:40  mhaveman
+ *	Intermediate state.
+ *
+ *	Revision 1.1  1998/08/11 09:08:40  mhaveman
+ *	Intermediate state.
+ *
+ ****************************************************************************/
+
+#ifndef _SKGEPNM2_H_
+#define _SKGEPNM2_H_
+
+/*
+ * General definitions
+ */
+#define SK_PNMI_CHIPSET_XMAC	1	/* XMAC11800FP */
+#define SK_PNMI_CHIPSET_YUKON	2	/* YUKON */
+
+#define	SK_PNMI_BUS_PCI		1	/* PCI bus*/
+
+/*
+ * Actions
+ */
+#define SK_PNMI_ACT_IDLE		1
+#define SK_PNMI_ACT_RESET		2
+#define SK_PNMI_ACT_SELFTEST	3
+#define SK_PNMI_ACT_RESETCNT	4
+
+/*
+ * VPD releated defines
+ */
+
+#define SK_PNMI_VPD_RW		1
+#define SK_PNMI_VPD_RO		2
+
+#define SK_PNMI_VPD_OK			0
+#define SK_PNMI_VPD_NOTFOUND	1
+#define SK_PNMI_VPD_CUT			2
+#define SK_PNMI_VPD_TIMEOUT		3
+#define SK_PNMI_VPD_FULL		4
+#define SK_PNMI_VPD_NOWRITE		5
+#define SK_PNMI_VPD_FATAL		6
+
+#define SK_PNMI_VPD_IGNORE	0
+#define SK_PNMI_VPD_CREATE	1
+#define SK_PNMI_VPD_DELETE	2
+
+
+/*
+ * RLMT related defines
+ */
+#define SK_PNMI_DEF_RLMT_CHG_THRES	240	/* 4 changes per minute */
+
+
+/*
+ * VCT internal status values
+ */
+#define SK_PNMI_VCT_PENDING	32
+#define SK_PNMI_VCT_TEST_DONE	64
+#define SK_PNMI_VCT_LINK	128
+
+/*
+ * Internal table definitions
+ */
+#define SK_PNMI_GET		0
+#define SK_PNMI_PRESET	1
+#define SK_PNMI_SET		2
+
+#define SK_PNMI_RO		0
+#define SK_PNMI_RW		1
+#define SK_PNMI_WO		2
+
+typedef struct s_OidTabEntry {
+	SK_U32			Id;
+	SK_U32			InstanceNo;
+	unsigned int	StructSize;
+	unsigned int	Offset;
+	int				Access;
+	int				(* Func)(SK_AC *pAc, SK_IOC pIo, int action,
+							 SK_U32 Id, char* pBuf, unsigned int* pLen,
+							 SK_U32 Instance, unsigned int TableIndex,
+							 SK_U32 NetNumber);
+	SK_U16			Param;
+} SK_PNMI_TAB_ENTRY;
+
+
+/*
+ * Trap lengths
+ */
+#define SK_PNMI_TRAP_SIMPLE_LEN			17
+#define SK_PNMI_TRAP_SENSOR_LEN_BASE	46
+#define SK_PNMI_TRAP_RLMT_CHANGE_LEN	23
+#define SK_PNMI_TRAP_RLMT_PORT_LEN		23
+
+/*
+ * Number of MAC types supported
+ */
+#define SK_PNMI_MAC_TYPES	(SK_MAC_GMAC + 1)
+
+/*
+ * MAC statistic data list (overall set for MAC types used)
+ */
+enum SK_MACSTATS {
+	SK_PNMI_HTX				= 0,
+	SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETHIGH 	= SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETLOW,
+	SK_PNMI_HTX_BROADCAST,
+	SK_PNMI_HTX_MULTICAST,
+	SK_PNMI_HTX_UNICAST,
+	SK_PNMI_HTX_BURST,
+	SK_PNMI_HTX_PMACC,
+	SK_PNMI_HTX_MACC,
+	SK_PNMI_HTX_COL,
+	SK_PNMI_HTX_SINGLE_COL,
+	SK_PNMI_HTX_MULTI_COL,
+	SK_PNMI_HTX_EXCESS_COL,
+	SK_PNMI_HTX_LATE_COL,
+	SK_PNMI_HTX_DEFFERAL,
+	SK_PNMI_HTX_EXCESS_DEF,
+	SK_PNMI_HTX_UNDERRUN,
+	SK_PNMI_HTX_CARRIER,
+	SK_PNMI_HTX_UTILUNDER,
+	SK_PNMI_HTX_UTILOVER,
+	SK_PNMI_HTX_64,
+	SK_PNMI_HTX_127,
+	SK_PNMI_HTX_255,
+	SK_PNMI_HTX_511,
+	SK_PNMI_HTX_1023,
+	SK_PNMI_HTX_MAX,
+	SK_PNMI_HTX_LONGFRAMES,
+	SK_PNMI_HTX_SYNC,
+	SK_PNMI_HTX_SYNC_OCTET,
+	SK_PNMI_HTX_RESERVED,
+
+	SK_PNMI_HRX,
+	SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETHIGH	= SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETLOW,
+	SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETLOW,
+	SK_PNMI_HRX_BROADCAST,
+	SK_PNMI_HRX_MULTICAST,
+	SK_PNMI_HRX_UNICAST,
+	SK_PNMI_HRX_PMACC,
+	SK_PNMI_HRX_MACC,
+	SK_PNMI_HRX_PMACC_ERR,
+	SK_PNMI_HRX_MACC_UNKWN,
+	SK_PNMI_HRX_BURST,
+	SK_PNMI_HRX_MISSED,
+	SK_PNMI_HRX_FRAMING,
+	SK_PNMI_HRX_UNDERSIZE,
+	SK_PNMI_HRX_OVERFLOW,
+	SK_PNMI_HRX_JABBER,
+	SK_PNMI_HRX_CARRIER,
+	SK_PNMI_HRX_IRLENGTH,
+	SK_PNMI_HRX_SYMBOL,
+	SK_PNMI_HRX_SHORTS,
+	SK_PNMI_HRX_RUNT,
+	SK_PNMI_HRX_TOO_LONG,
+	SK_PNMI_HRX_FCS,
+	SK_PNMI_HRX_CEXT,
+	SK_PNMI_HRX_UTILUNDER,
+	SK_PNMI_HRX_UTILOVER,
+	SK_PNMI_HRX_64,
+	SK_PNMI_HRX_127,
+	SK_PNMI_HRX_255,
+	SK_PNMI_HRX_511,
+	SK_PNMI_HRX_1023,
+	SK_PNMI_HRX_MAX,
+	SK_PNMI_HRX_LONGFRAMES,
+
+	SK_PNMI_HRX_RESERVED,
+
+	SK_PNMI_MAX_IDX		/* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */
+};
+
+/*
+ * MAC specific data
+ */
+typedef struct s_PnmiStatAddr {
+	SK_U16		Reg;		/* MAC register containing the value */
+	SK_BOOL		GetOffset;	/* TRUE: Offset managed by PNMI (call GetStatVal())*/
+} SK_PNMI_STATADDR;
+
+
+/*
+ * SK_PNMI_STRUCT_DATA copy offset evaluation macros
+ */
+#define SK_PNMI_OFF(e)		((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_MAI_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_VPD_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e))
+#define SK_PNMI_SEN_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e))
+#define SK_PNMI_CHK_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e))
+#define SK_PNMI_STA_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e))
+#define SK_PNMI_CNF_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e))
+#define SK_PNMI_RLM_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e))
+#define SK_PNMI_MON_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e))
+#define SK_PNMI_TRP_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e))
+
+#define SK_PNMI_SET_STAT(b,s,o)	{SK_U32	Val32; char *pVal; \
+					Val32 = (s); \
+					pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorStatus)); \
+					SK_PNMI_STORE_U32(pVal, Val32); \
+					Val32 = (o); \
+					pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorOffset)); \
+					SK_PNMI_STORE_U32(pVal, Val32);}
+
+/*
+ * Time macros
+ */
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)	(t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)	(((t) * 100) / (SK_TICKS_PER_SEC))
+#endif
+
+/*
+ * Macros to work around alignment problems
+ */
+#ifndef SK_PNMI_STORE_U16
+#define SK_PNMI_STORE_U16(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1);}
+#endif
+
+#ifndef SK_PNMI_STORE_U32
+#define SK_PNMI_STORE_U32(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3);}
+#endif
+
+#ifndef SK_PNMI_STORE_U64
+#define SK_PNMI_STORE_U64(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3); \
+					*((char *)(p) + 4) = \
+						*(((char *)&(v)) + 4); \
+					*((char *)(p) + 5) = \
+						*(((char *)&(v)) + 5); \
+					*((char *)(p) + 6) = \
+						*(((char *)&(v)) + 6); \
+					*((char *)(p) + 7) = \
+						*(((char *)&(v)) + 7);}
+#endif
+
+#ifndef SK_PNMI_READ_U16
+#define SK_PNMI_READ_U16(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1);}
+#endif
+
+#ifndef SK_PNMI_READ_U32
+#define SK_PNMI_READ_U32(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3);}
+#endif
+
+#ifndef SK_PNMI_READ_U64
+#define SK_PNMI_READ_U64(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3); \
+					*(((char *)&(v)) + 4) = \
+						*((char *)(p) + 4); \
+					*(((char *)&(v)) + 5) = \
+						*((char *)(p) + 5); \
+					*(((char *)&(v)) + 6) = \
+						*((char *)(p) + 6); \
+					*(((char *)&(v)) + 7) = \
+						*((char *)(p) + 7);}
+#endif
+
+/*
+ * Macros for Debug
+ */
+#ifdef DEBUG
+
+#define SK_PNMI_CHECKFLAGS(vSt)	{if (pAC->Pnmi.MacUpdatedFlag > 0 || \
+					pAC->Pnmi.RlmtUpdatedFlag > 0 || \
+					pAC->Pnmi.SirqUpdatedFlag > 0) { \
+						SK_DBG_MSG(pAC, \
+						SK_DBGMOD_PNMI, \
+						SK_DBGCAT_CTRL,	\
+						("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \
+						vSt, \
+						pAC->Pnmi.MacUpdatedFlag, \
+						pAC->Pnmi.RlmtUpdatedFlag, \
+						pAC->Pnmi.SirqUpdatedFlag))}}
+
+#else	/* !DEBUG */
+
+#define SK_PNMI_CHECKFLAGS(vSt)	/* Nothing */
+
+#endif	/* !DEBUG */
+
+#endif	/* _SKGEPNM2_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h
new file mode 100644
index 0000000..7532313
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnmi.h
@@ -0,0 +1,1114 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.59 $
+ * Date:	$Date: 2002/12/16 14:03:50 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnmi.h,v $
+ *	Revision 1.59  2002/12/16 14:03:50  tschilli
+ *	New defines for VCT added.
+ *
+ *	Revision 1.58  2002/12/16 09:04:59  tschilli
+ *	Code for VCT handling added.
+ *
+ *	Revision 1.57  2002/09/26 12:41:05  tschilli
+ *	SK_PNMI_PORT BufPort entry in struct SK_PNMI added.
+ *
+ *	Revision 1.56  2002/08/16 11:10:41  rwahl
+ *	- Replaced c++ comment.
+ *
+ *	Revision 1.55  2002/08/09 15:40:21  rwahl
+ *	Editorial change (renamed ConfSpeedCap).
+ *
+ *	Revision 1.54  2002/08/09 11:06:07  rwahl
+ *	Added OID_SKGE_SPEED_CAP.
+ *
+ *	Revision 1.53  2002/08/09 09:45:28  rwahl
+ *	Added support for NDIS OID_PNP_xxx.
+ *	Editorial changes.
+ *
+ *	Revision 1.52  2002/08/06 17:54:07  rwahl
+ *	- Added speed cap to PNMI config struct.
+ *
+ *	Revision 1.51  2002/07/17 19:19:26  rwahl
+ *	- Added OID_SKGE_SPEED_MODE and OID_SKGE_SPEED_STATUS.
+ *	- Added SK_PNMI_CNT_RX_PMACC_ERR() & SK_PNMI_CNT_RX_LONGFRAMES().
+ *	- Added speed mode & status to PNMI config struct.
+ *	- Editorial changes.
+ *
+ *	Revision 1.50  2002/05/22 08:59:37  rwahl
+ *	Added string definitions for error msgs.
+ *
+ *	Revision 1.49  2001/11/20 09:23:50  rwahl
+ *	- pnmi struct: reordered and aligned to 32bit.
+ *
+ *	Revision 1.48  2001/02/23 14:34:24  mkunz
+ *	Changed macro PHYS2INST. Added pAC to Interface
+ *
+ *	Revision 1.47  2001/02/07 08:28:23  mkunz
+ *	- Added Oids: 	OID_SKGE_DIAG_ACTION
+ *					OID_SKGE_DIAG_RESULT
+ *					OID_SKGE_MULTICAST_LIST
+ *					OID_SKGE_CURRENT_PACKET_FILTER
+ *					OID_SKGE_INTERMEDIATE_SUPPORT
+ *	- Changed value of OID_SKGE_MTU
+ *
+ *	Revision 1.46  2001/02/06 10:01:41  mkunz
+ *	- Pnmi V4 dual net support added. Interface functions and macros extended
+ *	- Vpd bug fixed
+ *	- OID_SKGE_MTU added
+ *
+ *	Revision 1.45  2001/01/22 13:41:37  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.44  2000/09/07 07:35:27  rwahl
+ *	- removed NDIS counter specific data type.
+ *	- fixed spelling for OID_SKGE_RLMT_PORT_PREFERRED.
+ *
+ *	Revision 1.43  2000/08/04 11:41:08  rwahl
+ *	- Fixed compiler warning (port is always >= 0) for macros
+ *	  SK_PNMI_CNT_RX_LONGFRAMES & SK_PNMI_CNT_SYNC_OCTETS
+ *
+ *	Revision 1.42  2000/08/03 15:14:07  rwahl
+ *	- Corrected error in driver macros addressing a physical port.
+ *
+ *	Revision 1.41  2000/08/01 16:22:29  rwahl
+ *	- Changed MDB version to 3.1.
+ *	- Added definitions for StatRxLongFrames counter.
+ *	- Added macro to be used by driver to count long frames received.
+ *	- Added directive to control width (default = 32bit) of NDIS statistic
+ *	  counters (SK_NDIS_64BIT_CTR).
+ *
+ *	Revision 1.40  2000/03/31 13:51:34  rwahl
+ *	Added SK_UPTR cast to offset calculation for PNMI struct fields;
+ *	missing cast caused compiler warnings by Win64 compiler.
+ *
+ *	Revision 1.39  1999/12/06 10:09:47  rwahl
+ *	Added new error log message.
+ *
+ *	Revision 1.38  1999/11/22 13:57:55  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.37  1999/09/14 14:25:32  rwahl
+ *	Set MDB version for 1000Base-T (sensors, Master/Slave) changes.
+ *
+ *	Revision 1.36  1999/05/20 09:24:56  cgoos
+ *	Changes for 1000Base-T (sensors, Master/Slave).
+ *
+ *	Revision 1.35  1999/04/13 15:10:51  mhaveman
+ *	Replaced RLMT macros SK_RLMT_CHECK_xxx again by those of PNMI to
+ *	grant unified interface. But PNMI macros will store the same
+ *	value as RLMT macros.
+ *
+ *	Revision 1.34  1999/04/13 15:03:49  mhaveman
+ *	-Changed copyright
+ *	-Removed SK_PNMI_RLMT_MODE_CHK_xxx macros. Those of RLMT should be
+ *	 used.
+ *
+ *	Revision 1.33  1999/03/23 10:41:02  mhaveman
+ *	Changed comments.
+ *
+ *	Revision 1.32  1999/01/25 15:01:33  mhaveman
+ *	Added support for multiple simultaniously active ports.
+ *
+ *	Revision 1.31  1999/01/19 10:06:26  mhaveman
+ *	Added new error log message.
+ *
+ *	Revision 1.30  1999/01/05 10:34:49  mhaveman
+ *	Fixed little error in RlmtChangeEstimate calculation.
+ *
+ *	Revision 1.29  1999/01/05 09:59:41  mhaveman
+ *	Redesigned port switch average calculation to avoid 64bit
+ *	arithmetic.
+ *
+ *	Revision 1.28  1998/12/08 10:05:48  mhaveman
+ *	Defined macro SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ *	Revision 1.27  1998/12/03 14:39:35  mhaveman
+ *	Fixed problem that LSTAT was enumerated wrong.
+ *
+ *	Revision 1.26  1998/12/03 11:19:51  mhaveman
+ *	Changed contents of errlog message SK_PNMI_ERR016MSG
+ *
+ *	Revision 1.25  1998/12/01 10:40:04  mhaveman
+ *	Changed size of SensorNumber, ChecksumNumber and RlmtPortNumber in
+ *	SK_PNMI_STRUCT_DATA to be conform with OID definition.
+ *
+ *	Revision 1.24  1998/11/20 08:09:27  mhaveman
+ *	Added macros to convert between logical, physical port indexes and
+ *	instances.
+ *
+ *	Revision 1.23  1998/11/10 13:41:13  mhaveman
+ *	Needed to change interface, because NT driver needs a return value
+ *	of needed buffer space on TOO_SHORT errors. Therefore all
+ *	SkPnmiGet/Preset/Set functions now have a pointer to the length
+ *	parameter, where the needed space on error is returned.
+ *
+ *	Revision 1.22  1998/11/03 12:05:51  mhaveman
+ *	Added pAC parameter to counter macors.
+ *
+ *	Revision 1.21  1998/11/02 10:47:36  mhaveman
+ *	Added syslog messages for internal errors.
+ *
+ *	Revision 1.20  1998/10/30 15:49:36  mhaveman
+ *	-Removed unused SK_PNMI_UTILIZATION_BASE and EstOldCnt.
+ *	-Redefined SK_PNMI_CHG_EST_BASE to hundreds of seconds.
+ *
+ *	Revision 1.19  1998/10/29 15:38:44  mhaveman
+ *	Changed string lengths of PNMI_STRUCT_DATA structure because
+ *	string OIDs are now encoded with leading length ocetet.
+ *
+ *	Revision 1.18  1998/10/29 08:52:27  mhaveman
+ *	-Added byte to strings in PNMI_STRUCT_DATA structure.
+ *	-Shortened SK_PNMI_RLMT structure to SK_MAX_MACS elements.
+ *
+ *	Revision 1.17  1998/10/28 08:49:50  mhaveman
+ *	-Changed type of Instance back to SK_U32 because of VPD
+ *	-Changed type from SK_U8 to char of PciBusSpeed, PciBusWidth, PMD,
+ *	 and Connector.
+ *
+ *	Revision 1.16  1998/10/22 10:42:31  mhaveman
+ *	-Removed (SK_U32) casts for OIDs
+ *	-excluded NDIS OIDs when they are already defined with ifndef _NDIS_
+ *
+ *	Revision 1.15  1998/10/20 13:56:28  mhaveman
+ *	Headerfile includes now directly other header files to comile correctly.
+ *
+ *	Revision 1.14  1998/10/20 07:31:09  mhaveman
+ *	Made type changes to unsigned int where possible.
+ *
+ *	Revision 1.13  1998/10/19 10:53:13  mhaveman
+ *	-Casted OID definitions to SK_U32
+ *	-Renamed RlmtMAC... to RlmtPort...
+ *	-Changed wrong type of VpdEntriesList from SK_U32 to char *
+ *
+ *	Revision 1.12  1998/10/13 07:42:27  mhaveman
+ *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA
+ *	-Removed old cvs history entries
+ *	-Renamed MacNumber to PortNumber
+ *
+ *	Revision 1.11  1998/10/07 10:55:24  mhaveman
+ *	-Added OID_MDB_VERSION. Therefore was a renumbering of the VPD OIDs
+ *	 necessary.
+ *	-Added OID_GEN_ Ids to support the windows driver.
+ *
+ *	Revision 1.10  1998/09/30 13:41:10  mhaveman
+ *	Renamed some OIDs to reduce usage of 'MAC' which is replaced by 'PORT'.
+ *
+ *	Revision 1.9  1998/09/04 17:06:17  mhaveman
+ *	-Added SyncCounter as macro.
+ *	-Renamed OID_SKGE_.._NO_DESCR_CTS to OID_SKGE_.._NO_BUF_CTS.
+ *	-Added macros for driver description and version strings.
+ *
+ *	Revision 1.8  1998/09/04 14:36:52  mhaveman
+ *	Added OIDs and Structure to access value of macro counters which are
+ *	counted by the driver.
+ *
+ *	Revision 1.7  1998/09/04 11:59:36  mhaveman
+ *	Everything compiles now. Driver Macros for counting still missing.
+ *
+ ****************************************************************************/
+
+#ifndef _SKGEPNMI_H_
+#define _SKGEPNMI_H_
+
+/*
+ * Include dependencies
+ */
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skaddr.h"
+#include "h/skrlmt.h"
+#include "h/skvpd.h"
+
+/*
+ * Management Database Version
+ */
+#define SK_PNMI_MDB_VERSION		0x00030001	/* 3.1 */
+
+
+/*
+ * Event definitions
+ */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW		1	/* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW			2	/* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP			3	/* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW			4	/* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP			5	/* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER		6	/* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_UTILIZATION_TIMER	7	/* Timer event for Utiliza. */
+#define SK_PNMI_EVT_CLEAR_COUNTER		8	/* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET			9	/* XMAC will be reset */
+
+#define SK_PNMI_EVT_RLMT_PORT_UP		10	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN		11	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_SEGMENTATION	13	/* Two SP root bridges found */
+#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN	14	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP		15	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_SET_NETS		16	/* 1. Parameter is number of nets
+												1 = single net; 2 = dual net */
+#define SK_PNMI_EVT_VCT_RESET		17	/* VCT port reset timer event started with SET. */
+
+
+/*
+ * Return values
+ */
+#define SK_PNMI_ERR_OK				0
+#define SK_PNMI_ERR_GENERAL			1
+#define SK_PNMI_ERR_TOO_SHORT		2
+#define SK_PNMI_ERR_BAD_VALUE		3
+#define SK_PNMI_ERR_READ_ONLY		4
+#define SK_PNMI_ERR_UNKNOWN_OID		5
+#define SK_PNMI_ERR_UNKNOWN_INST	6
+#define SK_PNMI_ERR_UNKNOWN_NET 	7
+
+
+/*
+ * Return values of driver reset function SK_DRIVER_RESET() and
+ * driver event function SK_DRIVER_EVENT()
+ */
+#define SK_PNMI_ERR_OK			0
+#define SK_PNMI_ERR_FAIL		1
+
+
+/*
+ * Return values of driver test function SK_DRIVER_SELFTEST()
+ */
+#define SK_PNMI_TST_UNKNOWN		(1 << 0)
+#define SK_PNMI_TST_TRANCEIVER		(1 << 1)
+#define SK_PNMI_TST_ASIC		(1 << 2)
+#define SK_PNMI_TST_SENSOR		(1 << 3)
+#define SK_PNMI_TST_POWERMGMT		(1 << 4)
+#define SK_PNMI_TST_PCI			(1 << 5)
+#define SK_PNMI_TST_MAC			(1 << 6)
+
+
+/*
+ * RLMT specific definitions
+ */
+#define SK_PNMI_RLMT_STATUS_STANDBY	1
+#define SK_PNMI_RLMT_STATUS_ACTIVE	2
+#define SK_PNMI_RLMT_STATUS_ERROR	3
+
+#define SK_PNMI_RLMT_LSTAT_PHY_DOWN	1
+#define SK_PNMI_RLMT_LSTAT_AUTONEG	2
+#define SK_PNMI_RLMT_LSTAT_LOG_DOWN	3
+#define SK_PNMI_RLMT_LSTAT_LOG_UP	4
+#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5
+
+#define SK_PNMI_RLMT_MODE_CHK_LINK	(SK_RLMT_CHECK_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_RX	(SK_RLMT_CHECK_LOC_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_SPT	(SK_RLMT_CHECK_SEG)
+/* #define SK_PNMI_RLMT_MODE_CHK_EX */
+
+/*
+ * OID definition
+ */
+#ifndef _NDIS_	/* Check, whether NDIS already included OIDs */
+
+#define OID_GEN_XMIT_OK					0x00020101
+#define OID_GEN_RCV_OK					0x00020102
+#define OID_GEN_XMIT_ERROR				0x00020103
+#define OID_GEN_RCV_ERROR				0x00020104
+#define OID_GEN_RCV_NO_BUFFER			0x00020105
+
+/* #define OID_GEN_DIRECTED_BYTES_XMIT	0x00020201 */
+#define OID_GEN_DIRECTED_FRAMES_XMIT	0x00020202
+/* #define OID_GEN_MULTICAST_BYTES_XMIT	0x00020203 */
+#define OID_GEN_MULTICAST_FRAMES_XMIT	0x00020204
+/* #define OID_GEN_BROADCAST_BYTES_XMIT	0x00020205 */
+#define OID_GEN_BROADCAST_FRAMES_XMIT	0x00020206
+/* #define OID_GEN_DIRECTED_BYTES_RCV	0x00020207 */
+#define OID_GEN_DIRECTED_FRAMES_RCV		0x00020208
+/* #define OID_GEN_MULTICAST_BYTES_RCV	0x00020209 */
+#define OID_GEN_MULTICAST_FRAMES_RCV	0x0002020A
+/* #define OID_GEN_BROADCAST_BYTES_RCV	0x0002020B */
+#define OID_GEN_BROADCAST_FRAMES_RCV	0x0002020C
+#define OID_GEN_RCV_CRC_ERROR			0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH	0x0002020E
+
+#define OID_802_3_PERMANENT_ADDRESS		0x01010101
+#define OID_802_3_CURRENT_ADDRESS		0x01010102
+/* #define OID_802_3_MULTICAST_LIST		0x01010103 */
+/* #define OID_802_3_MAXIMUM_LIST_SIZE	0x01010104 */
+/* #define OID_802_3_MAC_OPTIONS		0x01010105 */
+
+#define OID_802_3_RCV_ERROR_ALIGNMENT	0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION	0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS	0x01020103
+#define OID_802_3_XMIT_DEFERRED			0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS	0x01020202
+#define OID_802_3_RCV_OVERRUN			0x01020203
+#define OID_802_3_XMIT_UNDERRUN			0x01020204
+#define OID_802_3_XMIT_TIMES_CRS_LOST	0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS	0x01020207
+
+/*
+ * PnP and PM OIDs
+ */
+#ifdef SK_POWER_MGMT
+#define OID_PNP_CAPABILITIES			0xFD010100
+#define OID_PNP_SET_POWER				0xFD010101
+#define OID_PNP_QUERY_POWER				0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN		0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN	0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP			0xFD010106
+#endif /* SK_POWER_MGMT */
+
+#endif /* _NDIS_ */
+
+#define OID_SKGE_MDB_VERSION			0xFF010100
+#define OID_SKGE_SUPPORTED_LIST			0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES			0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST		0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER		0xFF010104
+#define OID_SKGE_VPD_KEY				0xFF010105
+#define OID_SKGE_VPD_VALUE				0xFF010106
+#define OID_SKGE_VPD_ACCESS				0xFF010107
+#define OID_SKGE_VPD_ACTION				0xFF010108
+
+#define OID_SKGE_PORT_NUMBER			0xFF010110
+#define OID_SKGE_DEVICE_TYPE			0xFF010111
+#define OID_SKGE_DRIVER_DESCR			0xFF010112
+#define OID_SKGE_DRIVER_VERSION			0xFF010113
+#define OID_SKGE_HW_DESCR				0xFF010114
+#define OID_SKGE_HW_VERSION				0xFF010115
+#define OID_SKGE_CHIPSET				0xFF010116
+#define OID_SKGE_ACTION					0xFF010117
+#define OID_SKGE_RESULT					0xFF010118
+#define OID_SKGE_BUS_TYPE				0xFF010119
+#define OID_SKGE_BUS_SPEED				0xFF01011A
+#define OID_SKGE_BUS_WIDTH				0xFF01011B
+/* 0xFF01011C unused */
+#define OID_SKGE_DIAG_ACTION			0xFF01011D
+#define OID_SKGE_DIAG_RESULT			0xFF01011E
+#define OID_SKGE_MTU					0xFF01011F
+#define OID_SKGE_PHYS_CUR_ADDR			0xFF010120
+#define OID_SKGE_PHYS_FAC_ADDR			0xFF010121
+#define OID_SKGE_PMD					0xFF010122
+#define OID_SKGE_CONNECTOR				0xFF010123
+#define OID_SKGE_LINK_CAP				0xFF010124
+#define OID_SKGE_LINK_MODE				0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS		0xFF010126
+#define OID_SKGE_LINK_STATUS			0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP			0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE			0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS		0xFF01012A
+#define OID_SKGE_PHY_OPERATION_CAP		0xFF01012B
+#define OID_SKGE_PHY_OPERATION_MODE		0xFF01012C
+#define OID_SKGE_PHY_OPERATION_STATUS	0xFF01012D
+#define OID_SKGE_MULTICAST_LIST			0xFF01012E
+#define OID_SKGE_CURRENT_PACKET_FILTER	0xFF01012F
+
+#define OID_SKGE_TRAP					0xFF010130
+#define OID_SKGE_TRAP_NUMBER			0xFF010131
+
+#define OID_SKGE_RLMT_MODE				0xFF010140
+#define OID_SKGE_RLMT_PORT_NUMBER		0xFF010141
+#define OID_SKGE_RLMT_PORT_ACTIVE		0xFF010142
+#define OID_SKGE_RLMT_PORT_PREFERRED	0xFF010143
+#define OID_SKGE_INTERMEDIATE_SUPPORT	0xFF010160
+
+#define OID_SKGE_SPEED_CAP				0xFF010170
+#define OID_SKGE_SPEED_MODE				0xFF010171
+#define OID_SKGE_SPEED_STATUS			0xFF010172
+
+#define OID_SKGE_SENSOR_NUMBER			0xFF020100
+#define OID_SKGE_SENSOR_INDEX			0xFF020101
+#define OID_SKGE_SENSOR_DESCR			0xFF020102
+#define OID_SKGE_SENSOR_TYPE			0xFF020103
+#define OID_SKGE_SENSOR_VALUE			0xFF020104
+#define OID_SKGE_SENSOR_WAR_THRES_LOW	0xFF020105
+#define OID_SKGE_SENSOR_WAR_THRES_UPP	0xFF020106
+#define OID_SKGE_SENSOR_ERR_THRES_LOW	0xFF020107
+#define OID_SKGE_SENSOR_ERR_THRES_UPP	0xFF020108
+#define OID_SKGE_SENSOR_STATUS			0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS			0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS			0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME		0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME		0xFF02010D
+
+#define OID_SKGE_CHKSM_NUMBER			0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS		0xFF020111
+#define OID_SKGE_CHKSM_RX_UNABLE_CTS	0xFF020112
+#define OID_SKGE_CHKSM_RX_ERR_CTS		0xFF020113
+#define OID_SKGE_CHKSM_TX_OK_CTS		0xFF020114
+#define OID_SKGE_CHKSM_TX_UNABLE_CTS	0xFF020115
+
+#define OID_SKGE_STAT_TX				0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS			0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST		0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST		0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST		0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES		0xFF020125
+#define OID_SKGE_STAT_TX_BURST			0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC			0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC			0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL		0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL		0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL		0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL		0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL		0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF		0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN		0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER		0xFF020130
+/* #define OID_SKGE_STAT_TX_UTIL		0xFF020131 */
+#define OID_SKGE_STAT_TX_64				0xFF020132
+#define OID_SKGE_STAT_TX_127			0xFF020133
+#define OID_SKGE_STAT_TX_255			0xFF020134
+#define OID_SKGE_STAT_TX_511			0xFF020135
+#define OID_SKGE_STAT_TX_1023			0xFF020136
+#define OID_SKGE_STAT_TX_MAX			0xFF020137
+#define OID_SKGE_STAT_TX_SYNC			0xFF020138
+#define OID_SKGE_STAT_TX_SYNC_OCTETS	0xFF020139
+#define OID_SKGE_STAT_RX				0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS			0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST		0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST		0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST		0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC			0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC			0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR		0xFF020141
+#define OID_SKGE_STAT_RX_FLOWC_UNKWN	0xFF020142
+#define OID_SKGE_STAT_RX_BURST			0xFF020143
+#define OID_SKGE_STAT_RX_MISSED			0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING		0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW		0xFF020146
+#define OID_SKGE_STAT_RX_JABBER			0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER		0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH		0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL			0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS			0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT			0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT			0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG		0xFF02014E
+#define OID_SKGE_STAT_RX_FCS			0xFF02014F
+/* #define OID_SKGE_STAT_RX_UTIL		0xFF020150 */
+#define OID_SKGE_STAT_RX_64				0xFF020151
+#define OID_SKGE_STAT_RX_127			0xFF020152
+#define OID_SKGE_STAT_RX_255			0xFF020153
+#define OID_SKGE_STAT_RX_511			0xFF020154
+#define OID_SKGE_STAT_RX_1023			0xFF020155
+#define OID_SKGE_STAT_RX_MAX			0xFF020156
+#define OID_SKGE_STAT_RX_LONGFRAMES		0xFF020157
+
+#define OID_SKGE_RLMT_CHANGE_CTS		0xFF020160
+#define OID_SKGE_RLMT_CHANGE_TIME		0xFF020161
+#define OID_SKGE_RLMT_CHANGE_ESTIM		0xFF020162
+#define OID_SKGE_RLMT_CHANGE_THRES		0xFF020163
+
+#define OID_SKGE_RLMT_PORT_INDEX		0xFF020164
+#define OID_SKGE_RLMT_STATUS			0xFF020165
+#define OID_SKGE_RLMT_TX_HELLO_CTS		0xFF020166
+#define OID_SKGE_RLMT_RX_HELLO_CTS		0xFF020167
+#define OID_SKGE_RLMT_TX_SP_REQ_CTS		0xFF020168
+#define OID_SKGE_RLMT_RX_SP_CTS			0xFF020169
+
+#define OID_SKGE_RLMT_MONITOR_NUMBER	0xFF010150
+#define OID_SKGE_RLMT_MONITOR_INDEX		0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR		0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS		0xFF010153
+#define OID_SKGE_RLMT_MONITOR_TIMESTAMP	0xFF010154
+#define OID_SKGE_RLMT_MONITOR_ADMIN		0xFF010155
+
+#define OID_SKGE_TX_SW_QUEUE_LEN		0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX		0xFF020171
+#define OID_SKGE_TX_RETRY				0xFF020172
+#define OID_SKGE_RX_INTR_CTS			0xFF020173
+#define OID_SKGE_TX_INTR_CTS			0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS			0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS			0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO		0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS		0xFF020178
+#define OID_SKGE_RX_OCTETS_DELIV_CTS	0xFF020179
+#define OID_SKGE_RX_HW_ERROR_CTS		0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS		0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS			0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS			0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS		0xFF02017E
+#define OID_SKGE_SYSUPTIME				0xFF02017F
+
+#define OID_SKGE_ALL_DATA				0xFF020190
+
+/* Defines for VCT. */
+#define OID_SKGE_VCT_GET			0xFF020200
+#define OID_SKGE_VCT_SET			0xFF020201
+#define OID_SKGE_VCT_STATUS			0xFF020202
+
+
+/* VCT struct to store a backup copy of VCT data after a port reset. */
+typedef struct s_PnmiVct {
+	SK_U8			VctStatus;
+	SK_U8			PCableLen;
+	SK_U32			PMdiPairLen[4];
+	SK_U8			PMdiPairSts[4];
+} SK_PNMI_VCT;
+
+
+/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */
+#define SK_PNMI_VCT_NONE		0
+#define SK_PNMI_VCT_OLD_VCT_DATA	1
+#define SK_PNMI_VCT_NEW_VCT_DATA	2
+#define SK_PNMI_VCT_OLD_DSP_DATA	4
+#define SK_PNMI_VCT_NEW_DSP_DATA	8
+#define SK_PNMI_VCT_RUNNING		16
+
+
+/* VCT cable test status. */
+#define SK_PNMI_VCT_NORMAL_CABLE		0
+#define SK_PNMI_VCT_SHORT_CABLE			1
+#define SK_PNMI_VCT_OPEN_CABLE			2
+#define SK_PNMI_VCT_TEST_FAIL			3
+#define SK_PNMI_VCT_IMPEDANCE_MISMATCH		4
+
+#define	OID_SKGE_TRAP_SEN_WAR_LOW		500
+#define OID_SKGE_TRAP_SEN_WAR_UPP		501
+#define	OID_SKGE_TRAP_SEN_ERR_LOW		502
+#define OID_SKGE_TRAP_SEN_ERR_UPP		503
+#define OID_SKGE_TRAP_RLMT_CHANGE_THRES	520
+#define OID_SKGE_TRAP_RLMT_CHANGE_PORT	521
+#define OID_SKGE_TRAP_RLMT_PORT_DOWN	522
+#define OID_SKGE_TRAP_RLMT_PORT_UP		523
+#define OID_SKGE_TRAP_RLMT_SEGMENTATION	524
+
+
+/*
+ * Define error numbers and messages for syslog
+ */
+#define SK_PNMI_ERR001		(SK_ERRBASE_PNMI + 1)
+#define SK_PNMI_ERR001MSG	"SkPnmiGetStruct: Unknown OID"
+#define SK_PNMI_ERR002		(SK_ERRBASE_PNMI + 2)
+#define SK_PNMI_ERR002MSG	"SkPnmiGetStruct: Cannot read VPD keys"
+#define SK_PNMI_ERR003		(SK_ERRBASE_PNMI + 3)
+#define SK_PNMI_ERR003MSG	"OidStruct: Called with wrong OID"
+#define SK_PNMI_ERR004		(SK_ERRBASE_PNMI + 4)
+#define SK_PNMI_ERR004MSG	"OidStruct: Called with wrong action"
+#define SK_PNMI_ERR005		(SK_ERRBASE_PNMI + 5)
+#define SK_PNMI_ERR005MSG	"Perform: Cannot reset driver"
+#define SK_PNMI_ERR006		(SK_ERRBASE_PNMI + 6)
+#define SK_PNMI_ERR006MSG	"Perform: Unknown OID action command"
+#define SK_PNMI_ERR007		(SK_ERRBASE_PNMI + 7)
+#define SK_PNMI_ERR007MSG	"General: Driver description not initialized"
+#define SK_PNMI_ERR008		(SK_ERRBASE_PNMI + 8)
+#define SK_PNMI_ERR008MSG	"Addr: Tried to get unknown OID"
+#define SK_PNMI_ERR009		(SK_ERRBASE_PNMI + 9)
+#define SK_PNMI_ERR009MSG	"Addr: Unknown OID"
+#define SK_PNMI_ERR010		(SK_ERRBASE_PNMI + 10)
+#define SK_PNMI_ERR010MSG	"CsumStat: Unknown OID"
+#define SK_PNMI_ERR011		(SK_ERRBASE_PNMI + 11)
+#define SK_PNMI_ERR011MSG	"SensorStat: Sensor descr string too long"
+#define SK_PNMI_ERR012		(SK_ERRBASE_PNMI + 12)
+#define SK_PNMI_ERR012MSG	"SensorStat: Unknown OID"
+#define SK_PNMI_ERR013		(SK_ERRBASE_PNMI + 13)
+#define SK_PNMI_ERR013MSG	""
+#define SK_PNMI_ERR014		(SK_ERRBASE_PNMI + 14)
+#define SK_PNMI_ERR014MSG	"Vpd: Cannot read VPD keys"
+#define SK_PNMI_ERR015		(SK_ERRBASE_PNMI + 15)
+#define SK_PNMI_ERR015MSG	"Vpd: Internal array for VPD keys to small"
+#define SK_PNMI_ERR016		(SK_ERRBASE_PNMI + 16)
+#define SK_PNMI_ERR016MSG	"Vpd: Key string too long"
+#define SK_PNMI_ERR017		(SK_ERRBASE_PNMI + 17)
+#define SK_PNMI_ERR017MSG	"Vpd: Invalid VPD status pointer"
+#define SK_PNMI_ERR018		(SK_ERRBASE_PNMI + 18)
+#define SK_PNMI_ERR018MSG	"Vpd: VPD data not valid"
+#define SK_PNMI_ERR019		(SK_ERRBASE_PNMI + 19)
+#define SK_PNMI_ERR019MSG	"Vpd: VPD entries list string too long"
+#define SK_PNMI_ERR021		(SK_ERRBASE_PNMI + 21)
+#define SK_PNMI_ERR021MSG	"Vpd: VPD data string too long"
+#define SK_PNMI_ERR022		(SK_ERRBASE_PNMI + 22)
+#define SK_PNMI_ERR022MSG	"Vpd: VPD data string too long should be errored before"
+#define SK_PNMI_ERR023		(SK_ERRBASE_PNMI + 23)
+#define SK_PNMI_ERR023MSG	"Vpd: Unknown OID in get action"
+#define SK_PNMI_ERR024		(SK_ERRBASE_PNMI + 24)
+#define SK_PNMI_ERR024MSG	"Vpd: Unknown OID in preset/set action"
+#define SK_PNMI_ERR025		(SK_ERRBASE_PNMI + 25)
+#define SK_PNMI_ERR025MSG	"Vpd: Cannot write VPD after modify entry"
+#define SK_PNMI_ERR026		(SK_ERRBASE_PNMI + 26)
+#define SK_PNMI_ERR026MSG	"Vpd: Cannot update VPD"
+#define SK_PNMI_ERR027		(SK_ERRBASE_PNMI + 27)
+#define SK_PNMI_ERR027MSG	"Vpd: Cannot delete VPD entry"
+#define SK_PNMI_ERR028		(SK_ERRBASE_PNMI + 28)
+#define SK_PNMI_ERR028MSG	"Vpd: Cannot update VPD after delete entry"
+#define SK_PNMI_ERR029		(SK_ERRBASE_PNMI + 29)
+#define SK_PNMI_ERR029MSG	"General: Driver description string too long"
+#define SK_PNMI_ERR030		(SK_ERRBASE_PNMI + 30)
+#define SK_PNMI_ERR030MSG	"General: Driver version not initialized"
+#define SK_PNMI_ERR031		(SK_ERRBASE_PNMI + 31)
+#define SK_PNMI_ERR031MSG	"General: Driver version string too long"
+#define SK_PNMI_ERR032		(SK_ERRBASE_PNMI + 32)
+#define SK_PNMI_ERR032MSG	"General: Cannot read VPD Name for HW descr"
+#define SK_PNMI_ERR033		(SK_ERRBASE_PNMI + 33)
+#define SK_PNMI_ERR033MSG	"General: HW description string too long"
+#define SK_PNMI_ERR034		(SK_ERRBASE_PNMI + 34)
+#define SK_PNMI_ERR034MSG	"General: Unknown OID"
+#define SK_PNMI_ERR035		(SK_ERRBASE_PNMI + 35)
+#define SK_PNMI_ERR035MSG	"Rlmt: Unknown OID"
+#define SK_PNMI_ERR036		(SK_ERRBASE_PNMI + 36)
+#define SK_PNMI_ERR036MSG	""
+#define SK_PNMI_ERR037		(SK_ERRBASE_PNMI + 37)
+#define SK_PNMI_ERR037MSG	"Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
+#define SK_PNMI_ERR038		(SK_ERRBASE_PNMI + 38)
+#define SK_PNMI_ERR038MSG	"Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0"
+#define SK_PNMI_ERR039		(SK_ERRBASE_PNMI + 39)
+#define SK_PNMI_ERR039MSG	"RlmtStat: Unknown OID"
+#define SK_PNMI_ERR040		(SK_ERRBASE_PNMI + 40)
+#define SK_PNMI_ERR040MSG	"PowerManagement: Unknown OID"
+#define SK_PNMI_ERR041		(SK_ERRBASE_PNMI + 41)
+#define SK_PNMI_ERR041MSG	"MacPrivateConf: Unknown OID"
+#define SK_PNMI_ERR042		(SK_ERRBASE_PNMI + 42)
+#define SK_PNMI_ERR042MSG	"MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
+#define SK_PNMI_ERR043		(SK_ERRBASE_PNMI + 43)
+#define SK_PNMI_ERR043MSG	"MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
+#define SK_PNMI_ERR044		(SK_ERRBASE_PNMI + 44)
+#define SK_PNMI_ERR044MSG	"MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
+#define SK_PNMI_ERR045		(SK_ERRBASE_PNMI + 45)
+#define SK_PNMI_ERR045MSG	"MacPrivateConf: SK_HWEV_SET_SPEED returned not 0"
+#define SK_PNMI_ERR046		(SK_ERRBASE_PNMI + 46)
+#define SK_PNMI_ERR046MSG	"Monitor: Unknown OID"
+#define SK_PNMI_ERR047		(SK_ERRBASE_PNMI + 47)
+#define SK_PNMI_ERR047MSG	"SirqUpdate: Event function returns not 0"
+#define SK_PNMI_ERR048		(SK_ERRBASE_PNMI + 48)
+#define SK_PNMI_ERR048MSG	"RlmtUpdate: Event function returns not 0"
+#define SK_PNMI_ERR049		(SK_ERRBASE_PNMI + 49)
+#define SK_PNMI_ERR049MSG	"SkPnmiInit: Invalid size of 'CounterOffset' struct!!"
+#define SK_PNMI_ERR050		(SK_ERRBASE_PNMI + 50)
+#define SK_PNMI_ERR050MSG	"SkPnmiInit: Invalid size of 'StatAddr' table!!"
+#define SK_PNMI_ERR051		(SK_ERRBASE_PNMI + 51)
+#define SK_PNMI_ERR051MSG	"SkPnmiEvent: Port switch suspicious"
+#define SK_PNMI_ERR052		(SK_ERRBASE_PNMI + 52)
+#define SK_PNMI_ERR052MSG	""
+
+/*
+ * Management counter macros called by the driver
+ */
+#define SK_PNMI_SET_DRIVER_DESCR(pAC,v)	((pAC)->Pnmi.pDriverDescription = \
+	(char *)(v))
+
+#define SK_PNMI_SET_DRIVER_VER(pAC,v)	((pAC)->Pnmi.pDriverVersion = \
+	(char *)(v))
+
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \
+	{ \
+		(pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \
+		if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \
+			(pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \
+		} \
+	}
+#define SK_PNMI_CNT_TX_RETRY(pAC,p)	(((pAC)->Pnmi.Port[p].TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \
+	((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \
+	{ \
+		((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \
+		(pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \
+	}
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p)	(((pAC)->Pnmi.Port[p].ErrRecoveryCts)++);
+
+#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatSyncCts)++; \
+			(pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \
+		} \
+	}
+
+/*
+ * Conversion Macros
+ */
+#define SK_PNMI_PORT_INST2LOG(i)	((unsigned int)(i) - 1)
+#define SK_PNMI_PORT_LOG2INST(l)	((unsigned int)(l) + 1)
+#define SK_PNMI_PORT_PHYS2LOG(p)	((unsigned int)(p) + 1)
+#define SK_PNMI_PORT_LOG2PHYS(pAC,l)	((unsigned int)(l) - 1)
+#define SK_PNMI_PORT_PHYS2INST(pAC,p)	\
+	(pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2))
+#define SK_PNMI_PORT_INST2PHYS(pAC,i)	((unsigned int)(i) - 2)
+
+/*
+ * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
+ */
+#define SK_PNMI_VPD_KEY_SIZE	5
+#define SK_PNMI_VPD_BUFSIZE		(VPD_SIZE)
+#define SK_PNMI_VPD_ENTRIES		(VPD_SIZE / 4)
+#define SK_PNMI_VPD_DATALEN		128 /*  Number of data bytes */
+
+#define SK_PNMI_MULTICAST_LISTLEN	64
+#define SK_PNMI_SENSOR_ENTRIES		(SK_MAX_SENSORS)
+#define SK_PNMI_CHECKSUM_ENTRIES	3
+#define SK_PNMI_MAC_ENTRIES			(SK_MAX_MACS + 1)
+#define SK_PNMI_MONITOR_ENTRIES		20
+#define SK_PNMI_TRAP_ENTRIES		10
+#define SK_PNMI_TRAPLEN				128
+#define SK_PNMI_STRINGLEN1			80
+#define SK_PNMI_STRINGLEN2			25
+#define SK_PNMI_TRAP_QUEUE_LEN		512
+
+typedef struct s_PnmiVpd {
+	char			VpdKey[SK_PNMI_VPD_KEY_SIZE];
+	char			VpdValue[SK_PNMI_VPD_DATALEN];
+	SK_U8			VpdAccess;
+	SK_U8			VpdAction;
+} SK_PNMI_VPD;
+
+typedef struct s_PnmiSensor {
+	SK_U8			SensorIndex;
+	char			SensorDescr[SK_PNMI_STRINGLEN2];
+	SK_U8			SensorType;
+	SK_U32			SensorValue;
+	SK_U32			SensorWarningThresholdLow;
+	SK_U32			SensorWarningThresholdHigh;
+	SK_U32			SensorErrorThresholdLow;
+	SK_U32			SensorErrorThresholdHigh;
+	SK_U8			SensorStatus;
+	SK_U64			SensorWarningCts;
+	SK_U64			SensorErrorCts;
+	SK_U64			SensorWarningTimestamp;
+	SK_U64			SensorErrorTimestamp;
+} SK_PNMI_SENSOR;
+
+typedef struct s_PnmiChecksum {
+	SK_U64			ChecksumRxOkCts;
+	SK_U64			ChecksumRxUnableCts;
+	SK_U64			ChecksumRxErrCts;
+	SK_U64			ChecksumTxOkCts;
+	SK_U64			ChecksumTxUnableCts;
+} SK_PNMI_CHECKSUM;
+
+typedef struct s_PnmiStat {
+	SK_U64			StatTxOkCts;
+	SK_U64			StatTxOctetsOkCts;
+	SK_U64			StatTxBroadcastOkCts;
+	SK_U64			StatTxMulticastOkCts;
+	SK_U64			StatTxUnicastOkCts;
+	SK_U64			StatTxLongFramesCts;
+	SK_U64			StatTxBurstCts;
+	SK_U64			StatTxPauseMacCtrlCts;
+	SK_U64			StatTxMacCtrlCts;
+	SK_U64			StatTxSingleCollisionCts;
+	SK_U64			StatTxMultipleCollisionCts;
+	SK_U64			StatTxExcessiveCollisionCts;
+	SK_U64			StatTxLateCollisionCts;
+	SK_U64			StatTxDeferralCts;
+	SK_U64			StatTxExcessiveDeferralCts;
+	SK_U64			StatTxFifoUnderrunCts;
+	SK_U64			StatTxCarrierCts;
+	SK_U64			Dummy1; /* StatTxUtilization */
+	SK_U64			StatTx64Cts;
+	SK_U64			StatTx127Cts;
+	SK_U64			StatTx255Cts;
+	SK_U64			StatTx511Cts;
+	SK_U64			StatTx1023Cts;
+	SK_U64			StatTxMaxCts;
+	SK_U64			StatTxSyncCts;
+	SK_U64			StatTxSyncOctetsCts;
+	SK_U64			StatRxOkCts;
+	SK_U64			StatRxOctetsOkCts;
+	SK_U64			StatRxBroadcastOkCts;
+	SK_U64			StatRxMulticastOkCts;
+	SK_U64			StatRxUnicastOkCts;
+	SK_U64			StatRxLongFramesCts;
+	SK_U64			StatRxPauseMacCtrlCts;
+	SK_U64			StatRxMacCtrlCts;
+	SK_U64			StatRxPauseMacCtrlErrorCts;
+	SK_U64			StatRxMacCtrlUnknownCts;
+	SK_U64			StatRxBurstCts;
+	SK_U64			StatRxMissedCts;
+	SK_U64			StatRxFramingCts;
+	SK_U64			StatRxFifoOverflowCts;
+	SK_U64			StatRxJabberCts;
+	SK_U64			StatRxCarrierCts;
+	SK_U64			StatRxIRLengthCts;
+	SK_U64			StatRxSymbolCts;
+	SK_U64			StatRxShortsCts;
+	SK_U64			StatRxRuntCts;
+	SK_U64			StatRxCextCts;
+	SK_U64			StatRxTooLongCts;
+	SK_U64			StatRxFcsCts;
+	SK_U64			Dummy2; /* StatRxUtilization */
+	SK_U64			StatRx64Cts;
+	SK_U64			StatRx127Cts;
+	SK_U64			StatRx255Cts;
+	SK_U64			StatRx511Cts;
+	SK_U64			StatRx1023Cts;
+	SK_U64			StatRxMaxCts;
+} SK_PNMI_STAT;
+
+typedef struct s_PnmiConf {
+	char			ConfMacCurrentAddr[6];
+	char			ConfMacFactoryAddr[6];
+	SK_U8			ConfPMD;
+	SK_U8			ConfConnector;
+	SK_U8			ConfLinkCapability;
+	SK_U8			ConfLinkMode;
+	SK_U8			ConfLinkModeStatus;
+	SK_U8			ConfLinkStatus;
+	SK_U8			ConfFlowCtrlCapability;
+	SK_U8			ConfFlowCtrlMode;
+	SK_U8			ConfFlowCtrlStatus;
+	SK_U8			ConfPhyOperationCapability;
+	SK_U8			ConfPhyOperationMode;
+	SK_U8			ConfPhyOperationStatus;
+	SK_U8			ConfSpeedCapability;
+	SK_U8			ConfSpeedMode;
+	SK_U8			ConfSpeedStatus;
+} SK_PNMI_CONF;
+
+typedef struct s_PnmiRlmt {
+	SK_U32			RlmtIndex;
+	SK_U32			RlmtStatus;
+	SK_U64			RlmtTxHelloCts;
+	SK_U64			RlmtRxHelloCts;
+	SK_U64			RlmtTxSpHelloReqCts;
+	SK_U64			RlmtRxSpHelloCts;
+} SK_PNMI_RLMT;
+
+typedef struct s_PnmiRlmtMonitor {
+	SK_U32			RlmtMonitorIndex;
+	char			RlmtMonitorAddr[6];
+	SK_U64			RlmtMonitorErrorCts;
+	SK_U64			RlmtMonitorTimestamp;
+	SK_U8			RlmtMonitorAdmin;
+} SK_PNMI_RLMT_MONITOR;
+
+typedef struct s_PnmiRequestStatus {
+	SK_U32			ErrorStatus;
+	SK_U32			ErrorOffset;
+} SK_PNMI_REQUEST_STATUS;
+
+typedef struct s_PnmiStrucData {
+	SK_U32			MgmtDBVersion;
+	SK_PNMI_REQUEST_STATUS	ReturnStatus;
+	SK_U32			VpdFreeBytes;
+	char			VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE];
+	SK_U32			VpdEntriesNumber;
+	SK_PNMI_VPD		Vpd[SK_PNMI_VPD_ENTRIES];
+	SK_U32			PortNumber;
+	SK_U32			DeviceType;
+	char			DriverDescr[SK_PNMI_STRINGLEN1];
+	char			DriverVersion[SK_PNMI_STRINGLEN2];
+	char			HwDescr[SK_PNMI_STRINGLEN1];
+	char			HwVersion[SK_PNMI_STRINGLEN2];
+	SK_U16			Chipset;
+	SK_U32			MtuSize;
+	SK_U32			Action;
+	SK_U32			TestResult;
+	SK_U8			BusType;
+	SK_U8			BusSpeed;
+	SK_U8			BusWidth;
+	SK_U8			SensorNumber;
+	SK_PNMI_SENSOR	Sensor[SK_PNMI_SENSOR_ENTRIES];
+	SK_U8			ChecksumNumber;
+	SK_PNMI_CHECKSUM	Checksum[SK_PNMI_CHECKSUM_ENTRIES];
+	SK_PNMI_STAT	Stat[SK_PNMI_MAC_ENTRIES];
+	SK_PNMI_CONF	Conf[SK_PNMI_MAC_ENTRIES];
+	SK_U8			RlmtMode;
+	SK_U32			RlmtPortNumber;
+	SK_U8			RlmtPortActive;
+	SK_U8			RlmtPortPreferred;
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_U64			RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+	SK_PNMI_RLMT	Rlmt[SK_MAX_MACS];
+	SK_U32			RlmtMonitorNumber;
+	SK_PNMI_RLMT_MONITOR	RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
+	SK_U32			TrapNumber;
+	SK_U8			Trap[SK_PNMI_TRAP_QUEUE_LEN];
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			SysUpTime;
+} SK_PNMI_STRUCT_DATA;
+
+#define SK_PNMI_STRUCT_SIZE	(sizeof(SK_PNMI_STRUCT_DATA))
+#define SK_PNMI_MIN_STRUCT_SIZE	((unsigned int)(SK_UPTR)\
+				 &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes))
+														/*
+														 * ReturnStatus field
+														 * must be located
+														 * before VpdFreeBytes
+														 */
+
+/*
+ * Various definitions
+ */
+#define SK_PNMI_MAX_PROTOS		3
+
+#define SK_PNMI_CNT_NO			66	/* Must have the value of the enum
+									 * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK
+									 * for check while init phase 1
+									 */
+
+/*
+ * Estimate data structure
+ */
+typedef struct s_PnmiEstimate {
+	unsigned int	EstValueIndex;
+	SK_U64			EstValue[7];
+	SK_U64			Estimate;
+	SK_TIMER		EstTimer;
+} SK_PNMI_ESTIMATE;
+
+
+/*
+ * VCT timer data structure
+ */
+typedef struct s_VctTimer {
+	SK_TIMER		VctTimer;
+} SK_PNMI_VCT_TIMER;
+
+
+/*
+ * PNMI specific adapter context structure
+ */
+typedef struct s_PnmiPort {
+	SK_U64			StatSyncCts;
+	SK_U64			StatSyncOctetsCts;
+	SK_U64			StatRxLongFrameCts;
+	SK_U64			StatRxFrameTooLongCts;
+	SK_U64			StatRxPMaccErr;
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			RxShortZeroMark;
+	SK_U64			CounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			CounterHigh[SK_PNMI_CNT_NO];
+	SK_BOOL			ActiveFlag;
+	SK_U8			Align[3];
+} SK_PNMI_PORT;
+
+
+typedef struct s_PnmiData {
+	SK_PNMI_PORT	Port	[SK_MAX_MACS];
+	SK_PNMI_PORT	BufPort	[SK_MAX_MACS]; /* 2002-09-13 pweber  */
+	SK_U64			VirtualCounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			TestResult;
+	char			HwVersion[10];
+	SK_U16			Align01;
+
+	char			*pDriverDescription;
+	char			*pDriverVersion;
+
+	int				MacUpdatedFlag;
+	int				RlmtUpdatedFlag;
+	int				SirqUpdatedFlag;
+
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_PNMI_ESTIMATE	RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+
+	SK_U64			StartUpTime;
+	SK_U32			DeviceType;
+	char			PciBusSpeed;
+	char			PciBusWidth;
+	char			Chipset;
+	char			PMD;
+	char			Connector;
+	SK_BOOL			DualNetActiveFlag;
+	SK_U16			Align02;
+
+	char			TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+	unsigned int	TrapBufFree;
+	unsigned int	TrapQueueBeg;
+	unsigned int	TrapQueueEnd;
+	unsigned int	TrapBufPad;
+	unsigned int	TrapUnique;
+	SK_U8		VctStatus[SK_MAX_MACS];
+	SK_PNMI_VCT	VctBackup[SK_MAX_MACS];
+	SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS];
+} SK_PNMI;
+
+
+/*
+ * Function prototypes
+ */
+extern int SkPnmiInit(SK_AC *pAc, SK_IOC IoC, int level);
+extern int SkPnmiGetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
+	unsigned int* pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiPreSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id,
+	void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiGetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiPreSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiEvent(SK_AC *pAc, SK_IOC IoC, SK_U32 Event,
+	SK_EVPARA Param);
+
+#endif
diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h
new file mode 100644
index 0000000..fc001b23
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgesirq.h
@@ -0,0 +1,194 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 2002/10/14 09:52:36 $
+ * Purpose:	SK specific Gigabit Ethernet special IRQ functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skgesirq.h,v $
+ *	Revision 1.26  2002/10/14 09:52:36  rschmidt
+ *	Added SKERR_SIRQ_E023 and SKERR_SIRQ_E023 for GPHY (Yukon)
+ *	Editorial changes
+ *
+ *	Revision 1.25  2002/07/15 18:15:52  rwahl
+ *	Editorial changes.
+ *
+ *	Revision 1.24  2002/07/15 15:39:21  rschmidt
+ *	Corrected define for SKERR_SIRQ_E022
+ *	Editorial changes
+ *
+ *	Revision 1.23  2002/04/25 11:09:45  rschmidt
+ *	Removed declarations for SkXmInitPhy(), SkXmRxTxEnable()
+ *	Editorial changes
+ *
+ *	Revision 1.22  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *
+ *	Revision 1.21  2000/10/18 12:22:40  cgoos
+ *	Added workaround for half duplex hangup.
+ *
+ *	Revision 1.20  1999/12/06 10:00:44  cgoos
+ *	Added SET event for role.
+ *
+ *	Revision 1.19  1999/11/22 13:58:26  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.18  1999/05/19 07:32:59  cgoos
+ *	Changes for 1000Base-T.
+ *
+ *	Revision 1.17  1999/03/12 13:29:31  malthoff
+ *	Move Autonegotiation Error Codes to skgeinit.h.
+ *
+ *	Revision 1.16  1999/03/08 10:11:28  gklug
+ *	add: AutoNegDone return codes
+ *
+ *	Revision 1.15  1998/11/18 13:20:53  gklug
+ *	add: different timeouts for active and non-active links
+ *
+ *	Revision 1.14  1998/11/04 07:18:14  cgoos
+ *	Added prototype for SkXmRxTxEnable.
+ *
+ *	Revision 1.13  1998/10/21 05:52:23  gklug
+ *	add: parameter DoLoop to InitPhy function
+ *
+ *	Revision 1.12  1998/10/19 06:45:03  cgoos
+ *	Added prototype for SkXmInitPhy.
+ *
+ *	Revision 1.11  1998/10/15 14:34:10  gklug
+ *	add: WA_TIME is 500 msec
+ *
+ *	Revision 1.10  1998/10/14 14:49:41  malthoff
+ *	Remove err log defines E021 and E022. They are
+ *	defined in skgeinit.h now.
+ *
+ *	Revision 1.9  1998/10/14 14:00:39  gklug
+ *	add: error logs for init phys
+ *
+ *	Revision 1.8  1998/10/14 05:44:05  gklug
+ *	add: E020
+ *
+ *	Revision 1.7  1998/10/02 06:24:58  gklug
+ *	add: error messages
+ *
+ *	Revision 1.6  1998/10/01 07:54:45  gklug
+ *	add: PNMI debug module
+ *
+ *	Revision 1.5  1998/09/28 13:36:31  malthoff
+ *	Move the bit definitions for Autonegotiation
+ *	and Flow Control to skgeinit.h.
+ *
+ *	Revision 1.4  1998/09/15 12:29:34  gklug
+ *	add: error logs
+ *
+ *	Revision 1.3  1998/09/03 13:54:02  gklug
+ *	add: function prototypes
+ *
+ *	Revision 1.2  1998/09/03 10:24:36  gklug
+ *	add: Events send by PNMI
+ *	add: parameter definition for Flow Control etc.
+ *
+ *	Revision 1.1  1998/08/27 11:50:27  gklug
+ *	initial revision
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKGESIRQ_H_
+#define _INC_SKGESIRQ_H_
+
+/*
+ * Define the Event the special IRQ/INI module can handle
+ */
+#define SK_HWEV_WATIM			1	/* Timeout for WA errata #2 XMAC */
+#define SK_HWEV_PORT_START		2	/* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP		3	/* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT		4	/* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT		5	/* Update Statistics by PNMI */
+#define SK_HWEV_SET_LMODE		6	/* Set Link Mode by PNMI */
+#define SK_HWEV_SET_FLOWMODE	7	/* Set Flow Control Mode by PNMI */
+#define SK_HWEV_SET_ROLE		8	/* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_SET_SPEED		9	/* Set Link Speed by PNMI */
+#define SK_HWEV_HALFDUP_CHK		10	/* Half Duplex Hangup Workaround */
+
+#define SK_WA_ACT_TIME		(5000000L)	/* 5 sec */
+#define SK_WA_INA_TIME		(100000L)	/* 100 msec */
+
+#define SK_HALFDUP_CHK_TIME	(10000L)	/* 10 msec */
+
+/*
+ * Define the error numbers and messages
+ */
+#define SKERR_SIRQ_E001		(SK_ERRBASE_SIRQ+0)
+#define SKERR_SIRQ_E001MSG	"Unknown event"
+#define SKERR_SIRQ_E002		(SKERR_SIRQ_E001+1)
+#define SKERR_SIRQ_E002MSG	"Packet timeout RX1"
+#define SKERR_SIRQ_E003		(SKERR_SIRQ_E002+1)
+#define SKERR_SIRQ_E003MSG	"Packet timeout RX2"
+#define SKERR_SIRQ_E004		(SKERR_SIRQ_E003+1)
+#define SKERR_SIRQ_E004MSG	"MAC 1 not correctly initialized"
+#define SKERR_SIRQ_E005		(SKERR_SIRQ_E004+1)
+#define SKERR_SIRQ_E005MSG	"MAC 2 not correctly initialized"
+#define SKERR_SIRQ_E006		(SKERR_SIRQ_E005+1)
+#define SKERR_SIRQ_E006MSG	"CHECK failure R1"
+#define SKERR_SIRQ_E007		(SKERR_SIRQ_E006+1)
+#define SKERR_SIRQ_E007MSG	"CHECK failure R2"
+#define SKERR_SIRQ_E008		(SKERR_SIRQ_E007+1)
+#define SKERR_SIRQ_E008MSG	"CHECK failure XS1"
+#define SKERR_SIRQ_E009		(SKERR_SIRQ_E008+1)
+#define SKERR_SIRQ_E009MSG	"CHECK failure XA1"
+#define SKERR_SIRQ_E010		(SKERR_SIRQ_E009+1)
+#define SKERR_SIRQ_E010MSG	"CHECK failure XS2"
+#define SKERR_SIRQ_E011		(SKERR_SIRQ_E010+1)
+#define SKERR_SIRQ_E011MSG	"CHECK failure XA2"
+#define SKERR_SIRQ_E012		(SKERR_SIRQ_E011+1)
+#define SKERR_SIRQ_E012MSG	"unexpected IRQ Master error"
+#define SKERR_SIRQ_E013		(SKERR_SIRQ_E012+1)
+#define SKERR_SIRQ_E013MSG	"unexpected IRQ Status error"
+#define SKERR_SIRQ_E014		(SKERR_SIRQ_E013+1)
+#define SKERR_SIRQ_E014MSG	"Parity error on RAM (read)"
+#define SKERR_SIRQ_E015		(SKERR_SIRQ_E014+1)
+#define SKERR_SIRQ_E015MSG	"Parity error on RAM (write)"
+#define SKERR_SIRQ_E016		(SKERR_SIRQ_E015+1)
+#define SKERR_SIRQ_E016MSG	"Parity error MAC 1"
+#define SKERR_SIRQ_E017		(SKERR_SIRQ_E016+1)
+#define SKERR_SIRQ_E017MSG	"Parity error MAC 2"
+#define SKERR_SIRQ_E018		(SKERR_SIRQ_E017+1)
+#define SKERR_SIRQ_E018MSG	"Parity error RX 1"
+#define SKERR_SIRQ_E019		(SKERR_SIRQ_E018+1)
+#define SKERR_SIRQ_E019MSG	"Parity error RX 2"
+#define SKERR_SIRQ_E020		(SKERR_SIRQ_E019+1)
+#define SKERR_SIRQ_E020MSG	"MAC transmit FIFO underrun"
+#define SKERR_SIRQ_E021		(SKERR_SIRQ_E020+1)
+#define SKERR_SIRQ_E021MSG	"Spurious TWSI interrupt"
+#define SKERR_SIRQ_E022		(SKERR_SIRQ_E021+1)
+#define SKERR_SIRQ_E022MSG	"Cable pair swap error"
+#define SKERR_SIRQ_E023		(SKERR_SIRQ_E022+1)
+#define SKERR_SIRQ_E023MSG	"Auto-negotiation error"
+#define SKERR_SIRQ_E024		(SKERR_SIRQ_E023+1)
+#define SKERR_SIRQ_E024MSG	"FIFO overflow error"
+
+extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
+extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkHWLinkUp(SK_AC *pAC, SK_IOC IoC, int Port);
+extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
+
+#endif	/* _INC_SKGESIRQ_H_ */
diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h
new file mode 100644
index 0000000..5ffaf6e
--- /dev/null
+++ b/drivers/net/sk98lin/h/ski2c.h
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.34 $
+ * Date:	$Date: 2003/01/28 09:11:21 $
+ * Purpose:	Defines to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: ski2c.h,v $
+ *	Revision 1.34  2003/01/28 09:11:21  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.33  2002/10/14 16:40:50  rschmidt
+ *	Editorial changes (TWSI)
+ *
+ *	Revision 1.32  2002/08/13 08:55:07  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.31  2002/08/06 09:44:22  jschmalz
+ *	Extensions and changes for Yukon
+ *
+ *	Revision 1.30  2001/04/05 11:38:09  rassmann
+ *	Set SenState to idle in SkI2cWaitIrq().
+ *	Changed error message in SkI2cWaitIrq().
+ *
+ *	Revision 1.29  2000/08/03 14:28:17  rassmann
+ *	- Added function to wait for I2C being ready before resetting the board.
+ *	- Replaced one duplicate "out of range" message with correct one.
+ *
+ *	Revision 1.28  1999/11/22 13:55:46  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.27  1999/05/20 09:23:10  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *
+ *	Revision 1.26  1998/12/01 13:45:47  gklug
+ *	add: InitLevel to I2c struct
+ *
+ *	Revision 1.25  1998/11/03 06:55:16  gklug
+ *	add: Dummy Reads to I2c struct
+ *
+ *	Revision 1.24  1998/10/02 14:28:59  cgoos
+ *	Added prototype for SkI2cIsr.
+ *
+ *	Revision 1.23  1998/09/08 12:20:11  gklug
+ *	add: prototypes for init and read functions
+ *
+ *	Revision 1.22  1998/09/08 07:37:56  gklug
+ *	add: log error if PCI_IO voltage sensor could not be initialized
+ *
+ *	Revision 1.21  1998/09/04 08:38:05  malthoff
+ *	Change the values for I2C_READ and I2C_WRITE
+ *
+ *	Revision 1.20  1998/08/25 07:52:22  gklug
+ *	chg: Timestamps (last) added for logging
+ *
+ *	Revision 1.19  1998/08/25 06:09:00  gklug
+ *	rmv: warning and error levels of the individual sensors.
+ *	add: timing definitions for sending traps and logging errors
+ *
+ *	Revision 1.18  1998/08/20 11:41:15  gklug
+ *	chg: omit STRCPY macro by using char * as Sensor Description
+ *
+ *	Revision 1.17  1998/08/20 11:37:43  gklug
+ *	chg: change Ioc to IoC
+ *
+ *	Revision 1.16  1998/08/20 11:30:38  gklug
+ *	fix: SenRead declaration
+ *
+ *	Revision 1.15  1998/08/20 11:27:53  gklug
+ *	fix: Compile bugs with new awrning constants
+ *
+ *	Revision 1.14  1998/08/20 08:53:12  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *
+ *	Revision 1.13  1998/08/19 12:21:16  gklug
+ *	fix: remove struct from C files (see CCC)
+ *	add: typedefs for all structs
+ *
+ *	Revision 1.12  1998/08/19 10:57:41  gklug
+ *	add: Warning levels
+ *
+ *	Revision 1.11  1998/08/18 08:37:02  malthoff
+ *	Prototypes not required for SK_DIAG.
+ *
+ *	Revision 1.10  1998/08/17 13:54:00  gklug
+ *	fix: declaration of event function
+ *
+ *	Revision 1.9  1998/08/17 06:48:39  malthoff
+ *	Remove some unrequired macros.
+ *	Fix the compiler errors.
+ *
+ *	Revision 1.8  1998/08/14 06:47:19  gklug
+ *	fix: Values are intergers
+ *
+ *	Revision 1.7  1998/08/14 06:26:05  gklug
+ *	add: Init error message
+ *
+ *	Revision 1.6  1998/08/13 08:31:08  gklug
+ *	add: Error message
+ *
+ *	Revision 1.5  1998/08/12 14:32:04  gklug
+ *	add: new error code/message
+ *
+ *	Revision 1.4  1998/08/12 13:39:08  gklug
+ *	chg: names of error messages
+ *	add: defines for Sensor type and thresholds
+ *
+ *	Revision 1.3  1998/08/11 07:57:16  gklug
+ *	add: sensor struct
+ *	add: Timeout defines
+ *	add: I2C control struct for pAC
+ *
+ *	Revision 1.2  1998/07/17 11:29:02  gklug
+ *	rmv: Microwire and SMTPANIC
+ *
+ *	Revision 1.1  1998/06/19 14:30:10  malthoff
+ *	Created. Sources taken from ML Project.
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKI2C.H	contains all I2C specific defines
+ */
+
+#ifndef _SKI2C_H_
+#define _SKI2C_H_
+
+typedef struct  s_Sensor SK_SENSOR;
+
+#include "h/skgei2c.h"
+
+/*
+ * Define the I2C events.
+ */
+#define SK_I2CEV_IRQ	1	/* IRQ happened Event */
+#define SK_I2CEV_TIM	2	/* Timeout event */
+#define SK_I2CEV_CLEAR	3	/* Clear MIB Values */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#undef	I2C_READ		/* just in case */
+#undef	I2C_WRITE		/* just in case */
+#define I2C_READ	0
+#define I2C_WRITE	1
+#define I2C_BURST	1
+#define I2C_SINGLE	0
+
+#define SKERR_I2C_E001		(SK_ERRBASE_I2C+0)
+#define SKERR_I2C_E001MSG	"Sensor index unknown"
+#define SKERR_I2C_E002		(SKERR_I2C_E001+1)
+#define SKERR_I2C_E002MSG	"TWSI: transfer does not complete"
+#define SKERR_I2C_E003		(SKERR_I2C_E002+1)
+#define SKERR_I2C_E003MSG	"LM80: NAK on device send"
+#define SKERR_I2C_E004		(SKERR_I2C_E003+1)
+#define SKERR_I2C_E004MSG	"LM80: NAK on register send"
+#define SKERR_I2C_E005		(SKERR_I2C_E004+1)
+#define SKERR_I2C_E005MSG	"LM80: NAK on device (2) send"
+#define SKERR_I2C_E006		(SKERR_I2C_E005+1)
+#define SKERR_I2C_E006MSG	"Unknown event"
+#define SKERR_I2C_E007		(SKERR_I2C_E006+1)
+#define SKERR_I2C_E007MSG	"LM80 read out of state"
+#define SKERR_I2C_E008		(SKERR_I2C_E007+1)
+#define SKERR_I2C_E008MSG	"Unexpected sensor read completed"
+#define SKERR_I2C_E009		(SKERR_I2C_E008+1)
+#define SKERR_I2C_E009MSG	"WARNING: temperature sensor out of range"
+#define SKERR_I2C_E010		(SKERR_I2C_E009+1)
+#define SKERR_I2C_E010MSG	"WARNING: voltage sensor out of range"
+#define SKERR_I2C_E011		(SKERR_I2C_E010+1)
+#define SKERR_I2C_E011MSG	"ERROR: temperature sensor out of range"
+#define SKERR_I2C_E012		(SKERR_I2C_E011+1)
+#define SKERR_I2C_E012MSG	"ERROR: voltage sensor out of range"
+#define SKERR_I2C_E013		(SKERR_I2C_E012+1)
+#define SKERR_I2C_E013MSG	"ERROR: couldn't init sensor"
+#define SKERR_I2C_E014		(SKERR_I2C_E013+1)
+#define SKERR_I2C_E014MSG	"WARNING: fan sensor out of range"
+#define SKERR_I2C_E015		(SKERR_I2C_E014+1)
+#define SKERR_I2C_E015MSG	"ERROR: fan sensor out of range"
+#define SKERR_I2C_E016		(SKERR_I2C_E015+1)
+#define SKERR_I2C_E016MSG	"TWSI: active transfer does not complete"
+
+/*
+ * Define Timeout values
+ */
+#define SK_I2C_TIM_LONG		2000000L	/* 2 seconds */
+#define SK_I2C_TIM_SHORT	 100000L	/* 100 milliseconds */
+#define SK_I2C_TIM_WATCH	1000000L	/* 1 second */
+
+/*
+ * Define trap and error log hold times
+ */
+#ifndef	SK_SEN_ERR_TR_HOLD
+#define SK_SEN_ERR_TR_HOLD		(4*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_ERR_LOG_HOLD
+#define SK_SEN_ERR_LOG_HOLD		(60*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_TR_HOLD
+#define SK_SEN_WARN_TR_HOLD		(15*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_LOG_HOLD
+#define SK_SEN_WARN_LOG_HOLD	(15*60*SK_TICKS_PER_SEC)
+#endif
+
+/*
+ * Defines for SenType
+ */
+#define SK_SEN_UNKNOWN	0
+#define SK_SEN_TEMP		1
+#define SK_SEN_VOLT		2
+#define SK_SEN_FAN		3
+
+/*
+ * Define for the SenErrorFlag
+ */
+#define SK_SEN_ERR_NOT_PRESENT	0	/* Error Flag: Sensor not present */
+#define SK_SEN_ERR_OK			1	/* Error Flag: O.K. */
+#define SK_SEN_ERR_WARN			2	/* Error Flag: Warning */
+#define SK_SEN_ERR_ERR			3	/* Error Flag: Error */
+#define SK_SEN_ERR_FAULTY		4	/* Error Flag: Faulty */
+
+/*
+ * Define the Sensor struct
+ */
+struct	s_Sensor {
+	char	*SenDesc;			/* Description */
+	int		SenType;			/* Voltage or Temperature */
+	SK_I32	SenValue;			/* Current value of the sensor */
+	SK_I32	SenThreErrHigh;		/* High error Threshhold of this sensor */
+	SK_I32	SenThreWarnHigh;	/* High warning Threshhold of this sensor */
+	SK_I32	SenThreErrLow;		/* Lower error Threshold of the sensor */
+	SK_I32	SenThreWarnLow;		/* Lower warning Threshold of the sensor */
+	int		SenErrFlag;			/* Sensor indicated an error */
+	SK_BOOL	SenInit;			/* Is sensor initialized ? */
+	SK_U64	SenErrCts;			/* Error  trap counter */
+	SK_U64	SenWarnCts;			/* Warning trap counter */
+	SK_U64	SenBegErrTS;		/* Begin error timestamp */
+	SK_U64	SenBegWarnTS;		/* Begin warning timestamp */
+	SK_U64	SenLastErrTrapTS;	/* Last error trap timestamp */
+	SK_U64	SenLastErrLogTS;	/* Last error log timestamp */
+	SK_U64	SenLastWarnTrapTS;	/* Last warning trap timestamp */
+	SK_U64	SenLastWarnLogTS;	/* Last warning log timestamp */
+	int		SenState;			/* Sensor State (see HW specific include) */
+	int		(*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen);
+								/* Sensors read function */
+	SK_U16	SenReg;				/* Register Address for this sensor */
+	SK_U8	SenDev;				/* Device Selection for this sensor */
+};
+
+typedef	struct	s_I2c {
+	SK_SENSOR	SenTable[SK_MAX_SENSORS];	/* Sensor Table */
+	int			CurrSens;	/* Which sensor is currently queried */
+	int			MaxSens;	/* Max. number of sensors */
+	int			TimerMode;	/* Use the timer also to watch the state machine */
+	int			InitLevel;	/* Initialized Level */
+#ifndef SK_DIAG
+	int			DummyReads;	/* Number of non-checked dummy reads */
+	SK_TIMER	SenTimer;	/* Sensors timer */
+#endif /* !SK_DIAG */
+} SK_I2C;
+
+extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#ifndef SK_DIAG
+extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
+extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC);
+extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
+
+#endif
+#endif /* n_SKI2C_H */
diff --git a/drivers/net/sk98lin/h/skqueue.h b/drivers/net/sk98lin/h/skqueue.h
new file mode 100644
index 0000000..bce20a7
--- /dev/null
+++ b/drivers/net/sk98lin/h/skqueue.h
@@ -0,0 +1,147 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 2002/03/15 10:52:13 $
+ * Purpose:	Defines for the Event queue
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skqueue.h,v $
+ *	Revision 1.14  2002/03/15 10:52:13  mkunz
+ *	Added event classes for link aggregation
+ *
+ *	Revision 1.13  1999/11/22 13:59:05  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.12  1998/09/08 08:48:01  gklug
+ *	add: init level handling
+ *
+ *	Revision 1.11  1998/09/03 14:15:11  gklug
+ *	add: CSUM and HWAC Eventclass and function.
+ *	fix: pParaPtr according to CCC
+ *
+ *	Revision 1.10  1998/08/20 12:43:03  gklug
+ *	add: typedef SK_QUEUE
+ *
+ *	Revision 1.9  1998/08/19 09:50:59  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.8  1998/08/18 07:00:01  gklug
+ *	fix: SK_PTR not defined use void * instead.
+ *
+ *	Revision 1.7  1998/08/17 13:43:19  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *
+ *	Revision 1.6  1998/08/14 07:09:30  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.5  1998/08/11 14:26:44  gklug
+ *	chg: Event Dispatcher returns now int.
+ *
+ *	Revision 1.4  1998/08/11 12:15:21  gklug
+ *	add: Error numbers of skqueue module
+ *
+ *	Revision 1.3  1998/08/07 12:54:23  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.2  1998/08/07 09:34:00  gklug
+ *	adapt structure defs to CCC
+ *	add: prototypes for functions
+ *
+ *	Revision 1.1  1998/07/30 14:52:12  gklug
+ *	Initial version.
+ *	Defines Event Classes, Event structs and queue management variables.
+ *
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKQUEUE.H	contains all defines and types for the event queue
+ */
+
+#ifndef _SKQUEUE_H_
+#define _SKQUEUE_H_
+
+
+/*
+ * define the event classes to be served
+ */
+#define	SKGE_DRV	1	/* Driver Event Class */
+#define	SKGE_RLMT	2	/* RLMT Event Class */
+#define	SKGE_I2C	3	/* i2C Event Class */
+#define	SKGE_PNMI	4	/* PNMI Event Class */
+#define	SKGE_CSUM	5	/* Checksum Event Class */
+#define	SKGE_HWAC	6	/* Hardware Access Event Class */
+
+#define	SKGE_SWT	9	/* Software Timer Event Class */
+#define	SKGE_LACP	10	/* LACP Aggregation Event Class */
+#define	SKGE_RSF	11	/* RSF Aggregation Event Class */
+#define	SKGE_MARKER	12	/* MARKER Aggregation Event Class */
+#define	SKGE_FD		13	/* FD Distributor Event Class */
+
+/*
+ * define event queue as circular buffer
+ */
+#define SK_MAX_EVENT	64
+
+/*
+ * Parameter union for the Para stuff
+ */
+typedef	union u_EvPara {
+	void	*pParaPtr;	/* Parameter Pointer */
+	SK_U64	Para64;		/* Parameter 64bit version */
+	SK_U32	Para32[2];	/* Parameter Array of 32bit parameters */
+} SK_EVPARA;
+
+/*
+ * Event Queue
+ *	skqueue.c
+ * events are class/value pairs
+ *	class	is addressee, e.g. RMT, PCM etc.
+ *	value	is command, e.g. line state change, ring op change etc.
+ */
+typedef	struct s_EventElem {
+	SK_U32		Class ;			/* Event class */
+	SK_U32		Event ;			/* Event value */
+	SK_EVPARA	Para ;			/* Event parameter */
+} SK_EVENTELEM;
+
+typedef	struct s_Queue {
+	SK_EVENTELEM	EvQueue[SK_MAX_EVENT];
+	SK_EVENTELEM	*EvPut ;
+	SK_EVENTELEM	*EvGet ;
+} SK_QUEUE;
+
+extern	void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern	void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event,
+	SK_EVPARA Para);
+extern	int SkEventDispatcher(SK_AC *pAC,SK_IOC Ioc);
+
+
+/* Define Error Numbers and messages */
+#define	SKERR_Q_E001	(SK_ERRBASE_QUEUE+0)
+#define	SKERR_Q_E001MSG	"Event queue overflow"
+#define	SKERR_Q_E002	(SKERR_Q_E001+1)
+#define	SKERR_Q_E002MSG	"Undefined event class"
+#endif	/* _SKQUEUE_H_ */
diff --git a/drivers/net/sk98lin/h/skrlmt.h b/drivers/net/sk98lin/h/skrlmt.h
new file mode 100644
index 0000000..04d025b
--- /dev/null
+++ b/drivers/net/sk98lin/h/skrlmt.h
@@ -0,0 +1,563 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.35 $
+ * Date:	$Date: 2003/01/31 14:12:41 $
+ * Purpose:	Header file for Redundant Link ManagemenT.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skrlmt.h,v $
+ *	Revision 1.35  2003/01/31 14:12:41  mkunz
+ *	single port adapter runs now with two identical MAC addresses
+ *
+ *	Revision 1.34  2002/09/23 15:13:41  rwahl
+ *	Editorial changes.
+ *
+ *	Revision 1.33  2001/07/03 12:16:48  mkunz
+ *	New Flag ChgBcPrio (Change priority of last broadcast received)
+ *
+ *	Revision 1.32  2001/02/14 14:06:31  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.31  2001/02/05 14:25:26  rassmann
+ *	Prepared RLMT for transparent operation.
+ *
+ *	Revision 1.30  2001/01/22 13:41:39  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.29  2000/11/17 08:58:00  rassmann
+ *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event.
+ *
+ *	Revision 1.28  2000/11/09 12:24:34  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.27  1999/11/22 13:59:56  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.26  1999/10/04 14:01:19  rassmann
+ *	Corrected reaction to reception of BPDU frames (#10441).
+ *
+ *	Revision 1.25  1999/07/20 12:53:39  rassmann
+ *	Fixed documentation errors for lookahead macros.
+ *
+ *	Revision 1.24  1999/05/28 11:15:56  rassmann
+ *	Changed behaviour to reflect Design Spec v1.2.
+ *	Controlling Link LED(s).
+ *	Introduced RLMT Packet Version field in RLMT Packet.
+ *	Newstyle lookahead macros (checking meta-information before looking at
+ *	  the packet).
+ *
+ *	Revision 1.23  1999/01/28 12:50:42  rassmann
+ *	Not using broadcast time stamps in CheckLinkState mode.
+ *
+ *	Revision 1.22  1999/01/27 14:13:04  rassmann
+ *	Monitoring broadcast traffic.
+ *	Switching more reliably and not too early if switch is
+ *	 configured for spanning tree.
+ *
+ *	Revision 1.21  1998/12/08 13:11:25  rassmann
+ *	Stopping SegTimer at RlmtStop.
+ *
+ *	Revision 1.20  1998/11/24 12:37:33  rassmann
+ *	Implemented segmentation check.
+ *
+ *	Revision 1.19  1998/11/17 13:43:06  rassmann
+ *	Handling (logical) tx failure.
+ *	Sending packet on logical address after PORT_SWITCH.
+ *
+ *	Revision 1.18  1998/11/13 16:56:56  rassmann
+ *	Added macro version of SkRlmtLookaheadPacket.
+ *
+ *	Revision 1.17  1998/11/06 18:06:05  rassmann
+ *	Corrected timing when RLMT checks fail.
+ *	Clearing tx counter earlier in periodical checks.
+ *
+ *	Revision 1.16  1998/11/03 13:53:50  rassmann
+ *	RLMT should switch now (at least in mode 3).
+ *
+ *	Revision 1.15  1998/10/22 11:39:52  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	Corrected receive list handling and address recognition.
+ *
+ *	Revision 1.14  1998/10/15 15:16:36  rassmann
+ *	Finished Spanning Tree checking.
+ *	Checked with lint.
+ *
+ *	Revision 1.13  1998/09/24 19:16:08  rassmann
+ *	Code cleanup.
+ *	Introduced Timer for PORT_DOWN due to no RX.
+ *
+ *	Revision 1.12  1998/09/16 11:09:52  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.11  1998/09/15 11:28:50  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.10  1998/09/14 17:07:38  rassmann
+ *	Added code for port checking via LAN.
+ *	Changed Mbuf definition.
+ *
+ *	Revision 1.9  1998/09/07 11:14:15  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.8  1998/09/07 09:06:08  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.7  1998/09/04 19:41:34  rassmann
+ *	Syntax corrections.
+ *	Started entering code for checking local links.
+ *
+ *	Revision 1.6  1998/09/04 12:14:28  rassmann
+ *	Interface cleanup.
+ *
+ *	Revision 1.5  1998/09/02 16:55:29  rassmann
+ *	Updated to reflect new DRV/HWAC/RLMT interface.
+ *
+ *	Revision 1.4  1998/09/02 07:26:02  afischer
+ *	typedef for SK_RLMT_PORT
+ *
+ *	Revision 1.3  1998/08/27 14:29:03  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.2  1998/08/27 14:26:25  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.1  1998/08/21 08:29:10  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the header file for Redundant Link ManagemenT.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	"skrlmt.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKRLMT_H
+#define __INC_SKRLMT_H
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define	SK_RLMT_NET_DOWN_TEMP	1	/* NET_DOWN due to last port down. */
+#define	SK_RLMT_NET_DOWN_FINAL	2	/* NET_DOWN due to RLMT_STOP. */
+
+/* ----- Default queue sizes - must be multiples of 8 KB ----- */
+
+/* Less than 8 KB free in RX queue => pause frames. */
+#define SK_RLMT_STANDBY_QRXSIZE	128	/* Size of rx standby queue in KB. */
+#define SK_RLMT_STANDBY_QXASIZE	32	/* Size of async standby queue in KB. */
+#define SK_RLMT_STANDBY_QXSSIZE	0	/* Size of sync standby queue in KB. */
+
+#define SK_RLMT_MAX_TX_BUF_SIZE	60	/* Maximum RLMT transmit size. */
+
+/* ----- PORT states ----- */
+
+#define SK_RLMT_PS_INIT			0	/* Port state: Init. */
+#define SK_RLMT_PS_LINK_DOWN	1	/* Port state: Link down. */
+#define SK_RLMT_PS_DOWN			2	/* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP		3	/* Port state: Going up. */
+#define SK_RLMT_PS_UP			4	/* Port state: Up. */
+
+/* ----- RLMT states ----- */
+
+#define SK_RLMT_RS_INIT			0	/* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN		1	/* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP		2	/* RLMT state: Net up. */
+
+/* ----- PORT events ----- */
+
+#define SK_RLMT_LINK_UP			1001	/* Link came up. */
+#define SK_RLMT_LINK_DOWN		1002	/* Link went down. */
+#define SK_RLMT_PORT_ADDR		1003	/* Port address changed. */
+
+/* ----- RLMT events ----- */
+
+#define SK_RLMT_START			2001	/* Start RLMT. */
+#define SK_RLMT_STOP			2002	/* Stop RLMT. */
+#define SK_RLMT_PACKET_RECEIVED	2003	/* Packet was received for RLMT. */
+#define SK_RLMT_STATS_CLEAR		2004	/* Clear statistics. */
+#define SK_RLMT_STATS_UPDATE	2005	/* Update statistics. */
+#define SK_RLMT_PREFPORT_CHANGE	2006	/* Change preferred port. */
+#define SK_RLMT_MODE_CHANGE		2007	/* New RlmtMode. */
+#define SK_RLMT_SET_NETS		2008	/* Number of Nets (1 or 2). */
+
+/* ----- RLMT mode bits ----- */
+
+/*
+ * CAUTION:	These defines are private to RLMT.
+ *			Please use the RLMT mode defines below.
+ */
+
+#define SK_RLMT_CHECK_LINK		  1		/* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK	  2		/* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG		  4		/* Check segmentation. */
+
+#ifndef RLMT_CHECK_REMOTE
+#define SK_RLMT_CHECK_OTHERS	SK_RLMT_CHECK_LOC_LINK
+#else	/* RLMT_CHECK_REMOTE */
+#define SK_RLMT_CHECK_REM_LINK	  8		/* Check link(s) on other adapter(s). */
+#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED	3
+#define SK_RLMT_CHECK_OTHERS	\
+		(SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+#endif	/* RLMT_CHECK_REMOTE */
+
+#ifndef SK_RLMT_ENABLE_TRANSPARENT
+#define SK_RLMT_TRANSPARENT		  0		/* RLMT transparent - inactive. */
+#else	/* SK_RLMT_ENABLE_TRANSPARENT */
+#define SK_RLMT_TRANSPARENT		128		/* RLMT transparent. */
+#endif	/* SK_RLMT_ENABLE_TRANSPARENT */
+
+/* ----- RLMT modes ----- */
+
+/* Check Link State. */
+#define SK_RLMT_MODE_CLS	(SK_RLMT_CHECK_LINK)
+
+/* Check Local Ports: check other links on the same adapter. */
+#define SK_RLMT_MODE_CLP	(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK)
+
+/* Check Local Ports and Segmentation Status. */
+#define SK_RLMT_MODE_CLPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG)
+
+#ifdef RLMT_CHECK_REMOTE
+/* Check Local and Remote Ports: check links (local or remote). */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRP	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+
+/* Check Local and Remote Ports and Segmentation Status. */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \
+		SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG)
+#endif	/* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT lookahead result bits ----- */
+
+#define SK_RLMT_RX_RLMT			1	/* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL		2	/* Give packet to protocol. */
+
+/* Macros */
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortNum		/* receiving port */
+unsigned	PktLen		/* received packet's length */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+unsigned	*pOffset	/* offs. of bytes to present to SK_RLMT_LOOKAHEAD */
+unsigned	*pNumBytes	/* #Bytes to present to SK_RLMT_LOOKAHEAD */
+#endif	/* 0 */
+
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortNum; \
+	_pAC = (pAC); \
+	_PortNum = (SK_U32)(PortNum); \
+	/* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \
+	_pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \
+    if (_pAC->Rlmt.RlmtOff) { \
+		*(pNumBytes) = 0; \
+    } \
+    else {\
+	if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \
+		*(pNumBytes) = 0; \
+	} \
+	else if (IsBc) { \
+		if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \
+			*(pNumBytes) = 6; \
+			*(pOffset) = 6; \
+		} \
+		else { \
+			*(pNumBytes) = 0; \
+		} \
+	} \
+	else { \
+		if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+			*(pNumBytes) = 0; \
+		} \
+		else { \
+			*(pNumBytes) = 6; \
+			*(pOffset) = 0; \
+		} \
+	} \
+    } \
+}
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortNum		/* receiving port */
+SK_U8		*pLaPacket,	/* received packet's data (points to pOffset) */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+SK_BOOL		IsMc		/* Flag: packet is multicast */
+unsigned	*pForRlmt	/* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */
+SK_RLMT_LOOKAHEAD() expects *pNumBytes from
+packet offset *pOffset (s.a.) at *pLaPacket.
+
+If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is
+BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
+can trash unneeded parts of the if construction.
+#endif	/* 0 */
+
+#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortNum; \
+	SK_U8	*_pLaPacket; \
+	_pAC = (pAC); \
+	_PortNum = (SK_U32)(PortNum); \
+	_pLaPacket = (SK_U8 *)(pLaPacket); \
+	if (IsBc) {\
+		if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \
+			_PortNum].Net->NetNumber].CurrentMacAddress.a)) { \
+			_pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \
+			_pAC->Rlmt.CheckSwitch = SK_TRUE; \
+		} \
+		/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+		*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+	} \
+	else if (IsMc) { \
+		if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
+			_pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \
+			if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \
+				*(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \
+			} \
+			else { \
+				*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+			} \
+		} \
+		else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+	else { \
+		if (SK_ADDR_EQUAL( \
+			_pLaPacket, \
+			_pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+}
+
+#ifdef SK_RLMT_FAST_LOOKAHEAD
+Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_FAST_LOOKAHEAD */
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
+
+/* typedefs *******************************************************************/
+
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+	some content
+} SK_RLMT_MBUF;
+#endif	/* SK_RLMT_MBUF_PRIVATE */
+
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+	unsigned	PacketLength;			/* Length of packet. */
+	unsigned	PacketType;				/* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif	/* SK_LA_INFO */
+
+
+typedef struct s_RootId {
+	SK_U8		Id[8];					/* Root Bridge Id. */
+} SK_RLMT_ROOT_ID;
+
+
+typedef struct s_port {
+	SK_MAC_ADDR	CheckAddr;
+	SK_BOOL		SuspectTx;
+} SK_PORT_CHECK;
+
+
+typedef struct s_RlmtNet SK_RLMT_NET;
+
+
+typedef struct s_RlmtPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U8			PortState;				/* Current state of this port. */
+
+	/* For PNMI */
+	SK_BOOL			LinkDown;
+	SK_BOOL			PortDown;
+	SK_U8			Align01;
+
+	SK_U32			PortNumber;				/* Number of port on adapter. */
+	SK_RLMT_NET *	Net;					/* Net port belongs to. */
+
+	SK_U64			TxHelloCts;
+	SK_U64			RxHelloCts;
+	SK_U64			TxSpHelloReqCts;
+	SK_U64			RxSpHelloCts;
+
+/* ----- Private part ----- */
+
+/*	SK_U64			PacketsRx; */				/* Total packets received. */
+	SK_U32			PacketsPerTimeSlot;		/* Packets rxed between TOs. */
+/*	SK_U32			DataPacketsPerTimeSlot; */	/* Data packets ... */
+	SK_U32			BpduPacketsPerTimeSlot;	/* BPDU packets rxed in TS. */
+	SK_U64			BcTimeStamp;			/* Time of last BC receive. */
+	SK_U64			GuTimeStamp;			/* Time of entering GOING_UP. */
+
+	SK_TIMER		UpTimer;				/* Timer struct Link/Port up. */
+	SK_TIMER		DownRxTimer;			/* Timer struct down rx. */
+	SK_TIMER		DownTxTimer;			/* Timer struct down tx. */
+
+	SK_U32			CheckingState;			/* Checking State. */
+
+	SK_ADDR_PORT *	AddrPort;
+
+	SK_U8			Random[4];				/* Random value. */
+	unsigned		PortsChecked;			/* #ports checked. */
+	unsigned		PortsSuspect;			/* #ports checked that are s. */
+	SK_PORT_CHECK	PortCheck[1];
+/*	SK_PORT_CHECK	PortCheck[SK_MAX_MACS - 1]; */
+
+	SK_BOOL			PortStarted;			/* Port is started. */
+	SK_BOOL			PortNoRx;				/* NoRx for >= 1 time slot. */
+	SK_BOOL			RootIdSet;
+	SK_RLMT_ROOT_ID	Root;					/* Root Bridge Id. */
+} SK_RLMT_PORT;
+
+
+struct s_RlmtNet {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U32			NetNumber;			/* Number of net. */
+
+	SK_RLMT_PORT *	Port[SK_MAX_MACS];	/* Ports that belong to this net. */
+	SK_U32			NumPorts;			/* Number of ports. */
+	SK_U32			PrefPort;			/* Preferred port. */
+
+	/* For PNMI */
+
+	SK_U32			ChgBcPrio;			/* Change Priority of last broadcast received */
+	SK_U32			RlmtMode;			/* Check ... */
+	SK_U32			ActivePort;			/* Active port. */
+	SK_U32			Preference;		/* 0xFFFFFFFF: Automatic. */
+
+	SK_U8			RlmtState;			/* Current RLMT state. */
+
+/* ----- Private part ----- */
+	SK_BOOL			RootIdSet;
+	SK_U16			Align01;
+
+	int				LinksUp;			/* #Links up. */
+	int				PortsUp;			/* #Ports up. */
+	SK_U32			TimeoutValue;		/* RLMT timeout value. */
+
+	SK_U32			CheckingState;		/* Checking State. */
+	SK_RLMT_ROOT_ID	Root;				/* Root Bridge Id. */
+
+	SK_TIMER		LocTimer;			/* Timer struct. */
+	SK_TIMER		SegTimer;			/* Timer struct. */
+};
+
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U32			NumNets;			/* Number of nets. */
+	SK_U32			NetsStarted;		/* Number of nets started. */
+	SK_RLMT_NET		Net[SK_MAX_NETS];	/* Array of available nets. */
+	SK_RLMT_PORT	Port[SK_MAX_MACS];	/* Array of available ports. */
+
+/* ----- Private part ----- */
+	SK_BOOL			CheckSwitch;
+	SK_BOOL			RlmtOff;            /* set to zero if the Mac addresses
+					   are equal or the second one
+					   is zero */
+	SK_U16			Align01;
+
+} SK_RLMT;
+
+
+extern	SK_MAC_ADDR	BridgeMcAddr;
+extern	SK_MAC_ADDR	SkRlmtMcAddr;
+
+/* function prototypes ********************************************************/
+
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	void	SkRlmtInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Level);
+
+extern	int	SkRlmtEvent(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		Event,
+	SK_EVPARA	Para);
+
+#else	/* defined(SK_KR_PROTO) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style function prototypes are not yet provided.
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKRLMT_H */
diff --git a/drivers/net/sk98lin/h/sktimer.h b/drivers/net/sk98lin/h/sktimer.h
new file mode 100644
index 0000000..36f8ccb
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktimer.h
@@ -0,0 +1,99 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/11/22 14:00:29 $
+ * Purpose:	Defines for the timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktimer.h,v $
+ *	Revision 1.9  1999/11/22 14:00:29  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.8  1998/09/08 08:48:02  gklug
+ *	add: init level handling
+ *
+ *	Revision 1.7  1998/08/20 12:31:29  gklug
+ *	fix: SK_TIMCTRL needs to be defined
+ *
+ *	Revision 1.6  1998/08/19 09:51:00  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.5  1998/08/17 13:43:21  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *
+ *	Revision 1.4  1998/08/14 07:09:31  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.3  1998/08/07 12:54:24  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.2  1998/08/07 09:35:29  gklug
+ *	add: Timer control struct for Adapters context
+ *	add: function prototypes
+ *
+ *	Revision 1.1  1998/08/05 11:27:01  gklug
+ *	First version: adapted from SMT
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKTIMER.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKTIMER_H_
+#define _SKTIMER_H_
+
+#include "h/skqueue.h"
+
+/*
+ * SK timer
+ * - needed wherever a timer is used. Put this in your data structure
+ *   wherever you want.
+ */
+typedef	struct s_Timer SK_TIMER;
+
+struct s_Timer {
+	SK_TIMER	*TmNext ;	/* linked list */
+	SK_U32		TmClass ;	/* Timer Event class */
+	SK_U32		TmEvent ;	/* Timer Event value */
+	SK_EVPARA	TmPara ;	/* Timer Event parameter */
+	SK_U32		TmDelta ;	/* delta time */
+	int		TmActive ;	/* flag : active/inactive */
+} ;
+
+/*
+ * Timer control struct.
+ * - use in Adapters context name pAC->Tim
+ */
+typedef	struct s_TimCtrl {
+	SK_TIMER	*StQueue ;	/* Head of Timer queue */
+} SK_TIMCTRL ;
+
+extern void SkTimerInit(SK_AC *pAC,SK_IOC Ioc, int Level);
+extern void SkTimerStop(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer);
+extern void SkTimerStart(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer,
+	SK_U32 Time,SK_U32 Class,SK_U32 Event,SK_EVPARA Para);
+extern void SkTimerDone(SK_AC *pAC,SK_IOC Ioc);
+#endif	/* _SKTIMER_H_ */
diff --git a/drivers/net/sk98lin/h/sktypes.h b/drivers/net/sk98lin/h/sktypes.h
new file mode 100644
index 0000000..e657016
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktypes.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Name:	sktypes.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.3 $
+ * Date:	$Date: 2003/02/25 14:16:40 $
+ * Purpose:	Define data types for Linux
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+ /*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktypes.h,v $
+ *	Revision 1.3  2003/02/25 14:16:40  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.2  1999/11/22 14:01:58  cgoos
+ *	Changed license header to GPL.
+ *	Now using Linux' fixed size types instead of standard types.
+ *
+ *	Revision 1.1  1999/02/16 07:41:40  cgoos
+ *	First version.
+ *
+ *
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * In this file, all data types that are needed by the common modules
+ * are mapped to Linux data types.
+ *
+ *
+ * Include File Hierarchy:
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+
+/* defines *******************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8	s8
+#define SK_U8	u8
+#define SK_I16	s16
+#define SK_U16	u16
+#define SK_I32	s32
+#define SK_U32	u32
+#define SK_I64	s64
+#define SK_U64	u64
+
+#define SK_UPTR	ulong		/* casting pointer <-> integral */
+
+/*
+* Boolean type.
+*/
+#define SK_BOOL		SK_U8
+#define SK_FALSE	0
+#define SK_TRUE		(!SK_FALSE)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif	/* __INC_SKTYPES_H */
diff --git a/drivers/net/sk98lin/h/skversion.h b/drivers/net/sk98lin/h/skversion.h
new file mode 100644
index 0000000..ef46685
--- /dev/null
+++ b/drivers/net/sk98lin/h/skversion.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Name:	version.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 2003/02/25 14:16:40 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skversion.h,v $
+ *	Revision 1.4  2003/02/25 14:16:40  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.3  2003/02/25 13:30:18  mlindner
+ *	Add: Support for various vendors
+ *
+ *	Revision 1.1.2.1  2001/09/05 13:38:30  mlindner
+ *	Removed FILE description
+ *
+ *	Revision 1.1  2001/03/06 09:25:00  mlindner
+ *	first version
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
+static const char SysKonnectBuildNumber[] =
+	"@(#)SK-BUILD: 6.05 PL: 01";
+
+#define BOOT_STRING	"sk98lin: Network Device Driver v6.05\n" \
+			"(C)Copyright 1999-2003 Marvell(R)."
+
+#define VER_STRING	"6.05"
diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h
new file mode 100644
index 0000000..1be34c5
--- /dev/null
+++ b/drivers/net/sk98lin/h/skvpd.h
@@ -0,0 +1,335 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.15 $
+ * Date:	$Date: 2003/01/13 10:39:38 $
+ * Purpose:	Defines and Macros for VPD handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skvpd.h,v $
+ *	Revision 1.15  2003/01/13 10:39:38  rschmidt
+ *	Replaced define for PCI device Id for YUKON with GENESIS
+ *	Editorial changes
+ *
+ *	Revision 1.14  2002/11/14 15:18:10  gheinig
+ *	Added const specifier to key and buf parameters for VpdPara,VpdRead
+ *	and VpdWrite. This is necessary for the Diag 7 GUI API
+ *
+ *	Revision 1.13  2002/10/14 15:58:18  rschmidt
+ *	Added entry in rom_size struct s_vpd
+ *	Editorial changes
+ *
+ *	Revision 1.12  2002/09/09 14:43:51  mkarl
+ *	added PCI Id of Yukon for reading VPD in diag before the adapter has
+ *	been initialized
+ *	editorial changes
+ *
+ *	Revision 1.11  2002/07/26 13:19:16  mkarl
+ *	added support for Yukon
+ *	added vpd_size to VPD struct
+ *
+ *	Revision 1.10  2000/08/10 11:29:07  rassmann
+ *	Editorial changes.
+ *	Preserving 32-bit alignment in structs for the adapter context.
+ *	Removed unused function VpdWriteDword() (#if 0).
+ *	Made VpdReadKeyword() available for SKDIAG only.
+ *
+ *	Revision 1.9  1999/11/22 14:02:27  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.8  1999/03/11 14:26:40  malthoff
+ *	Replace __STDC__ with SK_KR_PROTO.
+ *
+ *	Revision 1.7  1998/10/28 07:27:17  gklug
+ *	rmv: SWAP macros
+ *	add: VPD_IN/OUT8 macros
+ *	chg: interface definition
+ *
+ *	Revision 1.6  1998/10/22 10:03:44  gklug
+ *	fix: use SK_OUT16 instead of SK_OUTW
+ *
+ *	Revision 1.5  1998/10/14 07:05:31  cgoos
+ *	Changed constants in SK_SWAP_32 to UL.
+ *
+ *	Revision 1.4  1998/08/19 08:14:09  gklug
+ *	fix: remove struct keyword as much as possible from the C-code (see CCC)
+ *
+ *	Revision 1.3  1998/08/18 08:18:56  malthoff
+ *	Modify VPD in and out macros for SK_DIAG
+ *
+ *	Revision 1.2  1998/07/03 14:49:08  malthoff
+ *	Add VPD_INxx() and VPD_OUTxx() macros for the Diagnostics tool.
+ *
+ *	Revision 1.1  1998/06/19 14:08:03  malthoff
+ *	Created.
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * skvpd.h	contains Diagnostic specific defines for VPD handling
+ */
+
+#ifndef __INC_SKVPD_H_
+#define __INC_SKVPD_H_
+
+/*
+ * Define Resource Type Identifiers and VPD keywords
+ */
+#define	RES_ID		0x82	/* Resource Type ID String (Product Name) */
+#define RES_VPD_R	0x90	/* start of VPD read only area */
+#define RES_VPD_W	0x91	/* start of VPD read/write area */
+#define RES_END		0x78	/* Resource Type End Tag */
+
+#ifndef VPD_NAME
+#define VPD_NAME	"Name"	/* Product Name, VPD name of RES_ID */
+#endif	/* VPD_NAME */
+#define VPD_PN		"PN"	/* Adapter Part Number */
+#define	VPD_EC		"EC"	/* Adapter Engineering Level */
+#define VPD_MN		"MN"	/* Manufacture ID */
+#define VPD_SN		"SN"	/* Serial Number */
+#define VPD_CP		"CP"	/* Extended Capability */
+#define VPD_RV		"RV"	/* Checksum and Reserved */
+#define	VPD_YA		"YA"	/* Asset Tag Identifier */
+#define VPD_VL		"VL"	/* First Error Log Message (SK specific) */
+#define VPD_VF		"VF"	/* Second Error Log Message (SK specific) */
+#define VPD_RW		"RW"	/* Remaining Read / Write Area */
+
+/* 'type' values for vpd_setup_para() */
+#define VPD_RO_KEY	1	/* RO keys are "PN", "EC", "MN", "SN", "RV" */
+#define VPD_RW_KEY	2	/* RW keys are "Yx", "Vx", and "RW" */
+
+/* 'op' values for vpd_setup_para() */
+#define	ADD_KEY		1	/* add the key at the pos "RV" or "RW" */
+#define OWR_KEY		2	/* overwrite key if already exists */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+
+#define VPD_DEV_ID_GENESIS 	0x4300
+
+#define	VPD_SIZE_YUKON		256
+#define	VPD_SIZE_GENESIS	512
+#define	VPD_SIZE			512
+#define VPD_READ	0x0000
+#define VPD_WRITE	0x8000
+
+#define VPD_STOP(pAC,IoC)	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE)
+
+#define VPD_GET_RES_LEN(p)	((unsigned int) \
+					(* (SK_U8 *)&(p)[1]) |\
+					((* (SK_U8 *)&(p)[2]) << 8))
+#define VPD_GET_VPD_LEN(p)	((unsigned int)(* (SK_U8 *)&(p)[2]))
+#define VPD_GET_VAL(p)		((char *)&(p)[3])
+
+#define VPD_MAX_LEN	50
+
+/* VPD status */
+	/* bit 7..1 reserved */
+#define VPD_VALID	(1<<0)	/* VPD data buffer, vpd_free_ro, */
+							/* and vpd_free_rw valid	 */
+
+/*
+ * VPD structs
+ */
+typedef	struct s_vpd_status {
+	unsigned short	Align01;			/* Alignment */
+	unsigned short	vpd_status;			/* VPD status, description see above */
+	int				vpd_free_ro;		/* unused bytes in read only area */
+	int				vpd_free_rw;		/* bytes available in read/write area */
+} SK_VPD_STATUS;
+
+typedef	struct s_vpd {
+	SK_VPD_STATUS	v;					/* VPD status structure */
+	char			vpd_buf[VPD_SIZE];	/* VPD buffer */
+	int				rom_size;			/* VPD ROM Size from PCI_OUR_REG_2 */
+	int				vpd_size;			/* saved VPD-size */
+} SK_VPD;
+
+typedef	struct s_vpd_para {
+	unsigned int	p_len;	/* parameter length */
+	char			*p_val;	/* points to the value */
+} SK_VPD_PARA;
+
+/*
+ * structure of Large Resource Type Identifiers
+ */
+
+/* was removed because of alignment problems */
+
+/*
+ * structure of VPD keywords
+ */
+typedef	struct s_vpd_key {
+	char			p_key[2];	/* 2 bytes ID string */
+	unsigned char	p_len;		/* 1 byte length */
+	char			p_val;		/* start of the value string */
+} SK_VPD_KEY;
+
+
+/*
+ * System specific VPD macros
+ */
+#ifndef SKDIAG
+#ifndef VPD_DO_IO
+#define VPD_OUT8(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgByte(pAC,Addr,Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgWord(pAC,Addr,Val)
+#define VPD_OUT32(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgDWord(pAC,Addr,Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgByte(pAC,Addr,pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgWord(pAC,Addr,pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgDWord(pAC,Addr,pVal)
+#else	/* VPD_DO_IO */
+#define VPD_OUT8(pAC,IoC,Addr,Val)	SK_OUT8(IoC,PCI_C(Addr),Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	SK_OUT16(IoC,PCI_C(Addr),Val)
+#define VPD_OUT32(pAC,IoC,Addr,Val)	SK_OUT32(IoC,PCI_C(Addr),Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	SK_IN8(IoC,PCI_C(Addr),pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	SK_IN16(IoC,PCI_C(Addr),pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	SK_IN32(IoC,PCI_C(Addr),pVal)
+#endif	/* VPD_DO_IO */
+#else	/* SKDIAG */
+#define VPD_OUT8(pAC,Ioc,Addr,Val) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgByte(pAC,Addr,Val);	\
+		else									\
+			SK_OUT8(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_OUT16(pAC,Ioc,Addr,Val) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgWord(pAC,Addr,Val);	\
+		else						\
+			SK_OUT16(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_OUT32(pAC,Ioc,Addr,Val) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgDWord(pAC,Addr,Val);	\
+		else						\
+			SK_OUT32(pAC,PCI_C(Addr),Val); 		\
+		}
+#define VPD_IN8(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgByte(pAC,Addr,pVal);	\
+		else						\
+			SK_IN8(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN16(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgWord(pAC,Addr,pVal);	\
+		else						\
+			SK_IN16(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN32(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciReadCfgDWord(pAC,Addr,pVal);	\
+		else						\
+			SK_IN32(pAC,PCI_C(Addr),pVal);		\
+		}
+#endif	/* nSKDIAG */
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+#ifdef SKDIAG
+extern SK_U32	VpdReadDWord(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int			addr);
+#endif	/* SKDIAG */
+
+extern int	VpdSetupPara(
+	SK_AC		*pAC,
+	const char	*key,
+	const char	*buf,
+	int			len,
+	int			type,
+	int			op);
+
+extern SK_VPD_STATUS	*VpdStat(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+extern int	VpdKeys(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			*len,
+	int			*elements);
+
+extern int	VpdRead(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	const char	*key,
+	char		*buf,
+	int			*len);
+
+extern SK_BOOL	VpdMayWrite(
+	char		*key);
+
+extern int	VpdWrite(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	const char	*key,
+	const char	*buf);
+
+extern int	VpdDelete(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*key);
+
+extern int	VpdUpdate(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+extern void	VpdErrLog(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*msg);
+
+#ifdef	SKDIAG
+extern int	VpdReadBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			addr,
+	int			len);
+
+extern int	VpdWriteBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			addr,
+	int			len);
+#endif	/* SKDIAG */
+#else	/* SK_KR_PROTO */
+extern SK_U32	VpdReadDWord();
+extern int	VpdSetupPara();
+extern SK_VPD_STATUS	*VpdStat();
+extern int	VpdKeys();
+extern int	VpdRead();
+extern SK_BOOL	VpdMayWrite();
+extern int	VpdWrite();
+extern int	VpdDelete();
+extern int	VpdUpdate();
+extern void	VpdErrLog();
+#endif	/* SK_KR_PROTO */
+
+#endif	/* __INC_SKVPD_H_ */
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
new file mode 100644
index 0000000..2ef903a
--- /dev/null
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -0,0 +1,1738 @@
+/******************************************************************************
+ *
+ * Name:	xmac_ii.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.46 $
+ * Date:	$Date: 2003/01/28 09:47:45 $
+ * Purpose:	Defines and Macros for Gigabit Ethernet Controller
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: xmac_ii.h,v $
+ *	Revision 1.46  2003/01/28 09:47:45  rschmidt
+ *	Added defines for copper MDI/MDIX configuration
+ *	Added defines for LED Control Register
+ *	Editorial changes
+ *
+ *	Revision 1.45  2002/12/10 14:35:13  rschmidt
+ *	Corrected defines for Extended PHY Specific Control
+ *	Added defines for Ext. PHY Specific Ctrl 2 Reg. (Fiber specific)
+ *
+ *	Revision 1.44  2002/12/09 14:58:41  rschmidt
+ *	Added defines for Ext. PHY Specific Ctrl Reg. (downshift feature)
+ *	Added 'GMR_FS_UN_SIZE'-Bit to Rx GMAC FIFO Flush Mask
+ *
+ *	Revision 1.43  2002/12/05 10:14:45  rschmidt
+ *	Added define for GMAC's Half Duplex Burst Mode
+ *	Added define for Rx GMAC FIFO Flush Mask (default)
+ *
+ *	Revision 1.42  2002/11/12 16:48:19  rschmidt
+ *	Added defines for Cable Diagnostic Register (GPHY)
+ *	Editorial changes
+ *
+ *	Revision 1.41  2002/10/21 11:20:22  rschmidt
+ *	Added bit GMR_FS_GOOD_FC to GMR_FS_ANY_ERR
+ *	Editorial changes
+ *
+ *	Revision 1.40  2002/10/14 14:54:14  rschmidt
+ *	Added defines for GPHY Specific Status and GPHY Interrupt Status
+ *	Added bits PHY_M_IS_AN_ERROR and PHY_M_IS_FIFO_ERROR to PHY_M_DEF_MSK
+ *	Editorial changes
+ *
+ *	Revision 1.39  2002/10/10 15:53:44  mkarl
+ *	added some bit definitions for link speed status and LED's
+ *
+ *	Revision 1.38  2002/08/21 16:23:46  rschmidt
+ *	Added defines for PHY Specific Ctrl Reg
+ *	Editorial changes
+ *
+ *	Revision 1.37  2002/08/16 14:50:33  rschmidt
+ *	Added defines for Auto-Neg. Advertisement YUKON Fiber (88E1011S only)
+ *	Changed define PHY_M_DEF_MSK for GPHY IRQ Mask
+ *	Editorial changes
+ *
+ *	Revision 1.36  2002/08/12 13:21:10  rschmidt
+ *	Added defines for different Broadcom PHY Ids
+ *
+ *	Revision 1.35  2002/08/08 15:58:01  rschmidt
+ *	Added defines for Manual LED Override register (YUKON)
+ *	Editorial changes
+ *
+ *	Revision 1.34  2002/07/31 17:23:36  rwahl
+ *	Added define GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR).
+ *
+ *	Revision 1.33  2002/07/23 16:03:37  rschmidt
+ *	Added defines for GPHY registers
+ *	Editorial changes
+ *
+ *	Revision 1.32  2002/07/15 18:14:37  rwahl
+ *	Added GMAC MIB counters definitions.
+ *	Editorial changes.
+ *
+ *	Revision 1.31  2002/07/15 15:42:50  rschmidt
+ *	Removed defines from PHY specific reg. which are
+ *	common to all PHYs
+ *	Added defines for GMAC MIB Counters
+ *	Editorial changes
+ *
+ *	Revision 1.30  2002/06/05 08:22:12  rschmidt
+ *	Changed defines for GMAC Rx Control Register and Rx Status
+ *	Editorial changes
+ *
+ *	Revision 1.29  2002/04/25 11:43:56  rschmidt
+ *	Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res.
+ *	Added new registers and defines for YUKON (GMAC, GPHY)
+ *	Added Receive Frame Status Encoding for YUKON
+ *	Editorial changes
+ *
+ *	Revision 1.28  2000/11/09 12:32:49  rassmann
+ *	Renamed variables.
+ *
+ *	Revision 1.27  2000/05/17 11:00:46  malthoff
+ *	Add bit for enable/disable power management in BCOM chip.
+ *
+ *	Revision 1.26  1999/11/22 14:03:00  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.25  1999/08/12 19:19:38  malthoff
+ *	Add PHY_B_AC_TX_TST bit according to BCOM A1 errata sheet.
+ *
+ *	Revision 1.24  1999/07/30 11:27:21  cgoos
+ *	Fixed a missing end-of-comment.
+ *
+ *	Revision 1.23  1999/07/30 07:03:31  malthoff
+ *	Cut some long comments.
+ *	Correct the XMAC PHY ID definitions.
+ *
+ *	Revision 1.22  1999/05/19 07:33:18  cgoos
+ *	Changes for 1000Base-T.
+ *
+ *	Revision 1.21  1999/03/25 07:46:11  malthoff
+ *	Add XM_HW_CFG, XM_TS_READ, and XM_TS_LOAD registers.
+ *
+ *	Revision 1.20  1999/03/12 13:36:09  malthoff
+ *	Remove __STDC__.
+ *
+ *	Revision 1.19  1998/12/10 12:22:54  gklug
+ *	fix: RX_PAGE must be in interrupt mask
+ *
+ *	Revision 1.18  1998/12/10 10:36:36  gklug
+ *	fix: swap of pause bits
+ *
+ *	Revision 1.17  1998/11/18 13:21:45  gklug
+ *	fix: Default interrupt mask
+ *
+ *	Revision 1.16  1998/10/29 15:53:21  gklug
+ *	fix: Default mask uses ASS (GP0) signal
+ *
+ *	Revision 1.15  1998/10/28 13:52:52  malthoff
+ *	Add new bits in RX_CMD register.
+ *
+ *	Revision 1.14  1998/10/19 15:34:53  gklug
+ *	fix: typos
+ *
+ *	Revision 1.13  1998/10/14 07:19:03  malthoff
+ *	bug fix: Every define which describes bit 31
+ *	must be declared as unsigned long 'UL'.
+ *	fix bit definitions of PHY_AN_RFB and PHY_AN_PAUSE.
+ *	Remove ANP defines. Rework the RFB defines.
+ *
+ *	Revision 1.12  1998/10/14 06:22:44  cgoos
+ *	Changed shifted constant to ULONG.
+ *
+ *	Revision 1.11  1998/10/14 05:43:26  gklug
+ *	add: shift pause coding
+ *	fix: PAUSE bits definition
+ *
+ *	Revision 1.10  1998/10/13 09:19:21  malthoff
+ *	Again change XMR_FS_ANY_ERR because of new info from XaQti.
+ *
+ *	Revision 1.9  1998/10/09 07:58:30  malthoff
+ *	Add XMR_FS_FCS_ERR to XMR_FS_ANY_ERR.
+ *
+ *	Revision 1.8  1998/10/09 07:18:17  malthoff
+ *	bug fix of a bug fix: XM_PAUSE_MODE and XM_DEF_MODE
+ *	are not inverted! Bug XM_DEF_MSK is inverted.
+ *
+ *	Revision 1.7  1998/10/05 08:04:32  malthoff
+ *	bug fix: XM_PAUSE_MODE and XM_DEF_MODE
+ *	must be inverted declarations.
+ *
+ *	Revision 1.6  1998/09/28 13:38:18  malthoff
+ *	Add default modes and masks XM_DEF_MSK,
+ *	XM_PAUSE_MODE and XM_DEF_MODE
+ *
+ *	Revision 1.5  1998/09/16 14:42:04  malthoff
+ *	Bug Fix: XM_GP_PORT is a 32 bit (not a 16 bit) register.
+ *
+ *	Revision 1.4  1998/08/20 14:59:47  malthoff
+ *	Rework this file after reading the XaQti data sheet
+ *	"Differences between Rev. B2 & Rev. C XMAC II".
+ *	This file is now 100% XMAC II Rev. C complained.
+ *
+ *	Revision 1.3  1998/06/29 12:18:23  malthoff
+ *	Correct XMR_FS_ANY_ERR definition.
+ *
+ *	Revision 1.2  1998/06/29 12:10:56  malthoff
+ *	Add define XMR_FS_ANY_ERR.
+ *
+ *	Revision 1.1  1998/06/19 13:37:17  malthoff
+ *	created.
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_XMAC_H
+#define __INC_XMAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * XMAC II registers
+ *
+ * The XMAC registers are 16 or 32 bits wide.
+ * The XMACs host processor interface is set to 16 bit mode,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the XMAC registers
+ * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_INHASH(), and XM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+#define XM_MMU_CMD		0x0000	/* 16 bit r/w	MMU Command Register */
+	/* 0x0004:		reserved */
+#define XM_POFF			0x0008	/* 32 bit r/w	Packet Offset Register */
+#define XM_BURST		0x000c	/* 32 bit r/w	Burst Register for half duplex*/
+#define XM_1L_VLAN_TAG	0x0010	/* 16 bit r/w	One Level VLAN Tag ID */
+#define XM_2L_VLAN_TAG	0x0014	/* 16 bit r/w	Two Level VLAN Tag ID */
+	/* 0x0018 - 0x001e:	reserved */
+#define XM_TX_CMD		0x0020	/* 16 bit r/w	Transmit Command Register */
+#define XM_TX_RT_LIM	0x0024	/* 16 bit r/w	Transmit Retry Limit Register */
+#define XM_TX_STIME		0x0028	/* 16 bit r/w	Transmit Slottime Register */
+#define XM_TX_IPG		0x002c	/* 16 bit r/w	Transmit Inter Packet Gap */
+#define XM_RX_CMD		0x0030	/* 16 bit r/w	Receive Command Register */
+#define XM_PHY_ADDR		0x0034	/* 16 bit r/w	PHY Address Register */
+#define XM_PHY_DATA		0x0038	/* 16 bit r/w	PHY Data Register */
+	/* 0x003c: 		reserved */
+#define XM_GP_PORT		0x0040	/* 32 bit r/w	General Purpose Port Register */
+#define XM_IMSK			0x0044	/* 16 bit r/w	Interrupt Mask Register */
+#define XM_ISRC			0x0048	/* 16 bit r/o	Interrupt Status Register */
+#define XM_HW_CFG		0x004c	/* 16 bit r/w	Hardware Config Register */
+	/* 0x0050 - 0x005e:	reserved */
+#define XM_TX_LO_WM		0x0060	/* 16 bit r/w	Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM		0x0062	/* 16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_THR		0x0064	/* 16 bit r/w	Tx Request Threshold */
+#define XM_HT_THR		0x0066	/* 16 bit r/w	Host Request Threshold */
+#define XM_PAUSE_DA		0x0068	/* NA reg r/w	Pause Destination Address */
+	/* 0x006e: 		reserved */
+#define XM_CTL_PARA		0x0070	/* 32 bit r/w	Control Parameter Register */
+#define XM_MAC_OPCODE	0x0074	/* 16 bit r/w	Opcode for MAC control frames */
+#define XM_MAC_PTIME	0x0076	/* 16 bit r/w	Pause time for MAC ctrl frames*/
+#define XM_TX_STAT		0x0078	/* 32 bit r/o	Tx Status LIFO Register */
+
+	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exact Match Address Registers */
+	/* 				use the XM_EXM() macro to address */
+#define XM_EXM_START	0x0080	/* r/w	Start Address of the EXM Regs */
+
+	/*
+	 * XM_EXM(Reg)
+	 *
+	 * returns the XMAC address offset of specified Exact Match Addr Reg
+	 *
+	 * para:	Reg	EXM register to addr	(0 .. 15)
+	 *
+	 * usage:	XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]);
+	 */
+#define XM_EXM(Reg)	(XM_EXM_START + ((Reg) << 3))
+
+#define XM_SRC_CHK		0x0100	/* NA reg r/w	Source Check Address Register */
+#define XM_SA			0x0108	/* NA reg r/w	Station Address Register */
+#define XM_HSM			0x0110	/* 64 bit r/w	Hash Match Address Registers */
+#define XM_RX_LO_WM		0x0118	/* 16 bit r/w	Receive Low Water Mark */
+#define XM_RX_HI_WM		0x011a	/* 16 bit r/w	Receive High Water Mark */
+#define XM_RX_THR		0x011c	/* 32 bit r/w	Receive Request Threshold */
+#define XM_DEV_ID		0x0120	/* 32 bit r/o	Device ID Register */
+#define XM_MODE			0x0124	/* 32 bit r/w	Mode Register */
+#define XM_LSA			0x0128	/* NA reg r/o	Last Source Register */
+	/* 0x012e:		reserved */
+#define XM_TS_READ		0x0130	/* 32 bit r/o	Time Stamp Read Register */
+#define XM_TS_LOAD		0x0134	/* 32 bit r/o	Time Stamp Load Value */
+	/* 0x0138 - 0x01fe:	reserved */
+#define XM_STAT_CMD	0x0200	/* 16 bit r/w	Statistics Command Register */
+#define XM_RX_CNT_EV	0x0204	/* 32 bit r/o	Rx Counter Event Register */
+#define XM_TX_CNT_EV	0x0208	/* 32 bit r/o	Tx Counter Event Register */
+#define XM_RX_EV_MSK	0x020c	/* 32 bit r/w	Rx Counter Event Mask */
+#define XM_TX_EV_MSK	0x0210	/* 32 bit r/w	Tx Counter Event Mask */
+	/* 0x0204 - 0x027e:	reserved */
+#define XM_TXF_OK		0x0280	/* 32 bit r/o	Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI	0x0284	/* 32 bit r/o	Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO	0x0288	/* 32 bit r/o	Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK	0x028c	/* 32 bit r/o	Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK	0x0290	/* 32 bit r/o	Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK	0x0294	/* 32 bit r/o	Unicast Frames Xmitted OK */
+#define XM_TXF_LONG		0x0298	/* 32 bit r/o	Tx Long Frame Counter */
+#define XM_TXE_BURST	0x029c	/* 32 bit r/o	Tx Burst Event Counter */
+#define XM_TXF_MPAUSE	0x02a0	/* 32 bit r/o	Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL	0x02a4	/* 32 bit r/o	Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL	0x02a8	/* 32 bit r/o	Tx Single Collision Counter */
+#define XM_TXF_MUL_COL	0x02ac	/* 32 bit r/o	Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL	0x02b0	/* 32 bit r/o	Tx aborted due to Exces. Col. */
+#define XM_TXF_LAT_COL	0x02b4	/* 32 bit r/o	Tx Late Collision Counter */
+#define XM_TXF_DEF		0x02b8	/* 32 bit r/o	Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF	0x02bc	/* 32 bit r/o	Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR	0x02c0	/* 32 bit r/o	Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR	0x02c4	/* 32 bit r/o	Tx Carrier Sense Error Cnt */
+#define XM_TXP_UTIL		0x02c8	/* 32 bit r/o	Tx Utilization in % */
+	/* 0x02cc - 0x02ce:	reserved */
+#define XM_TXF_64B		0x02d0	/* 32 bit r/o	64 Byte Tx Frame Counter */
+#define XM_TXF_127B		0x02d4	/* 32 bit r/o	65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B		0x02d8	/* 32 bit r/o	128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B		0x02dc	/* 32 bit r/o	256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B	0x02e0	/* 32 bit r/o	512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ	0x02e4	/* 32 bit r/o	1024-MaxSize Byte Tx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+#define XM_RXF_OK		0x0300	/* 32 bit r/o	Frames Received OK */
+#define XM_RXO_OK_HI	0x0304	/* 32 bit r/o	Octets Received OK High Cnt */
+#define XM_RXO_OK_LO	0x0308	/* 32 bit r/o	Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK	0x030c	/* 32 bit r/o	Broadcast Frames Received OK */
+#define XM_RXF_MC_OK	0x0310	/* 32 bit r/o	Multicast Frames Received OK */
+#define XM_RXF_UC_OK	0x0314	/* 32 bit r/o	Unicast Frames Received OK */
+#define XM_RXF_MPAUSE	0x0318	/* 32 bit r/o	Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL	0x031c	/* 32 bit r/o	Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP	0x0320	/* 32 bit r/o	Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC	0x0324	/* 32 bit r/o	Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST	0x0328	/* 32 bit r/o	Rx Burst Event Counter */
+#define XM_RXE_FMISS	0x032c	/* 32 bit r/o	Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR	0x0330	/* 32 bit r/o	Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV	0x0334	/* 32 bit r/o	Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT	0x0338	/* 32 bit r/o	Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR	0x033c	/* 32 bit r/o	Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR	0x0340	/* 32 bit r/o	Rx in Range Length Error */
+#define XM_RXE_SYM_ERR	0x0344	/* 32 bit r/o	Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR	0x0348	/* 32 bit r/o	Rx Short Event Error Cnt */
+#define XM_RXE_RUNT		0x034c	/* 32 bit r/o	Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR	0x0350	/* 32 bit r/o	Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR	0x0354	/* 32 bit r/o	Rx Frame Check Seq. Error Cnt */
+	/* 0x0358 - 0x035a:	reserved */
+#define XM_RXF_CEX_ERR	0x035c	/* 32 bit r/o	Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL		0x0360	/* 32 bit r/o	Rx Utilization in % */
+	/* 0x0364 - 0x0366:	reserved */
+#define XM_RXF_64B		0x0368	/* 32 bit r/o	64 Byte Rx Frame Counter */
+#define XM_RXF_127B		0x036c	/* 32 bit r/o	65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B		0x0370	/* 32 bit r/o	128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B		0x0374	/* 32 bit r/o	256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B	0x0378	/* 32 bit r/o	512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ	0x037c	/* 32 bit r/o	1024-MaxSize Byte Rx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *	(sc)	self clearing
+ *	(ro)	read only
+ */
+
+/*	XM_MMU_CMD	16 bit r/w	MMU Command Register */
+								/* Bit 15..13:	reserved */
+#define XM_MMU_PHY_RDY	(1<<12)	/* Bit 12:	PHY Read Ready */
+#define XM_MMU_PHY_BUSY	(1<<11)	/* Bit 11:	PHY Busy */
+#define XM_MMU_IGN_PF	(1<<10)	/* Bit 10:	Ignore Pause Frame */
+#define XM_MMU_MAC_LB	(1<<9)	/* Bit  9:	Enable MAC Loopback */
+								/* Bit  8:	reserved */
+#define XM_MMU_FRC_COL	(1<<7)	/* Bit  7:	Force Collision */
+#define XM_MMU_SIM_COL	(1<<6)	/* Bit  6:	Simulate Collision */
+#define XM_MMU_NO_PRE	(1<<5)	/* Bit  5:	No MDIO Preamble */
+#define XM_MMU_GMII_FD	(1<<4)	/* Bit  4:	GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL	(1<<3)	/* Bit  3:	Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2)	/* Bit  2:	PHY is in Loopback Mode */
+#define XM_MMU_ENA_RX	(1<<1)	/* Bit  1:	Enable Receiver */
+#define XM_MMU_ENA_TX	(1<<0)	/* Bit  0:	Enable Transmitter */
+
+
+/*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
+								/* Bit 15..7:	reserved */
+#define XM_TX_BK2BK		(1<<6)	/* Bit  6:	Ignor Carrier Sense (Tx Bk2Bk)*/
+#define XM_TX_ENC_BYP	(1<<5)	/* Bit  5:	Set Encoder in Bypass Mode */
+#define XM_TX_SAM_LINE	(1<<4)	/* Bit  4: (sc)	Start utilization calculation */
+#define XM_TX_NO_GIG_MD	(1<<3)	/* Bit  3:	Disable Carrier Extension */
+#define XM_TX_NO_PRE	(1<<2)	/* Bit  2:	Disable Preamble Generation */
+#define XM_TX_NO_CRC	(1<<1)	/* Bit  1:	Disable CRC Generation */
+#define XM_TX_AUTO_PAD	(1<<0)	/* Bit  0:	Enable Automatic Padding */
+
+
+/*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
+								/* Bit 15..5:	reserved */
+#define XM_RT_LIM_MSK	0x1f	/* Bit  4..0:	Tx Retry Limit */
+
+
+/*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
+								/* Bit 15..7:	reserved */
+#define XM_STIME_MSK	0x7f	/* Bit  6..0:	Tx Slottime bits */
+
+
+/*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
+								/* Bit 15..8:	reserved */
+#define XM_IPG_MSK		0xff	/* Bit  7..0:	IPG value bits */
+
+
+/*	XM_RX_CMD	16 bit r/w	Receive Command Register */
+								/* Bit 15..9:	reserved */
+#define XM_RX_LENERR_OK (1<<8)	/* Bit  8	don't set Rx Err bit for */
+								/*		inrange error packets */
+#define XM_RX_BIG_PK_OK	(1<<7)	/* Bit  7	don't set Rx Err bit for */
+								/*		jumbo packets */
+#define XM_RX_IPG_CAP	(1<<6)	/* Bit  6	repl. type field with IPG */
+#define XM_RX_TP_MD		(1<<5)	/* Bit  5:	Enable transparent Mode */
+#define XM_RX_STRIP_FCS	(1<<4)	/* Bit  4:	Enable FCS Stripping */
+#define XM_RX_SELF_RX	(1<<3)	/* Bit  3: 	Enable Rx of own packets */
+#define XM_RX_SAM_LINE	(1<<2)	/* Bit  2: (sc)	Start utilization calculation */
+#define XM_RX_STRIP_PAD	(1<<1)	/* Bit  1:	Strip pad bytes of Rx frames */
+#define XM_RX_DIS_CEXT	(1<<0)	/* Bit  0:	Disable carrier ext. check */
+
+
+/*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
+								/* Bit 15..5:	reserved */
+#define XM_PHY_ADDR_SZ	0x1f	/* Bit  4..0:	PHY Address bits */
+
+
+/*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
+								/* Bit 31..7:	reserved */
+#define XM_GP_ANIP		(1L<<6)	/* Bit  6: (ro)	Auto-Neg. in progress */
+#define XM_GP_FRC_INT	(1L<<5)	/* Bit  5: (sc)	Force Interrupt */
+								/* Bit  4:	reserved */
+#define XM_GP_RES_MAC	(1L<<3)	/* Bit  3: (sc)	Reset MAC and FIFOs */
+#define XM_GP_RES_STAT	(1L<<2)	/* Bit  2: (sc)	Reset the statistics module */
+								/* Bit  1:	reserved */
+#define XM_GP_INP_ASS	(1L<<0)	/* Bit  0: (ro) GP Input Pin asserted */
+
+
+/*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
+/*	XM_ISRC		16 bit r/o	Interrupt Status Register */
+								/* Bit 15:	reserved */
+#define XM_IS_LNK_AE	(1<<14) /* Bit 14:	Link Asynchronous Event */
+#define XM_IS_TX_ABORT	(1<<13) /* Bit 13:	Transmit Abort, late Col. etc */
+#define XM_IS_FRC_INT	(1<<12) /* Bit 12:	Force INT bit set in GP */
+#define XM_IS_INP_ASS	(1<<11)	/* Bit 11:	Input Asserted, GP bit 0 set */
+#define XM_IS_LIPA_RC	(1<<10)	/* Bit 10:	Link Partner requests config */
+#define XM_IS_RX_PAGE	(1<<9)	/* Bit  9:	Page Received */
+#define XM_IS_TX_PAGE	(1<<8)	/* Bit  8:	Next Page Loaded for Transmit */
+#define XM_IS_AND		(1<<7)	/* Bit  7:	Auto-Negotiation Done */
+#define XM_IS_TSC_OV	(1<<6)	/* Bit  6:	Time Stamp Counter Overflow */
+#define XM_IS_RXC_OV	(1<<5)	/* Bit  5:	Rx Counter Event Overflow */
+#define XM_IS_TXC_OV	(1<<4)	/* Bit  4:	Tx Counter Event Overflow */
+#define XM_IS_RXF_OV	(1<<3)	/* Bit  3:	Receive FIFO Overflow */
+#define XM_IS_TXF_UR	(1<<2)	/* Bit  2:	Transmit FIFO Underrun */
+#define XM_IS_TX_COMP	(1<<1)	/* Bit  1:	Frame Tx Complete */
+#define XM_IS_RX_COMP	(1<<0)	/* Bit  0:	Frame Rx Complete */
+
+#define XM_DEF_MSK	(~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
+			XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR))
+
+
+/*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
+								/* Bit 15.. 4:	reserved */
+#define XM_HW_GEN_EOP	(1<<3)	/* Bit  3:	generate End of Packet pulse */
+#define XM_HW_COM4SIG	(1<<2)	/* Bit  2:	use Comma Detect for Sig. Det.*/
+								/* Bit  1:	reserved */
+#define XM_HW_GMII_MD	(1<<0)	/* Bit  0:	GMII Interface selected */
+
+
+/*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
+/*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
+								/* Bit 15..10	reserved */
+#define XM_TX_WM_MSK	0x01ff	/* Bit  9.. 0	Tx FIFO Watermark bits */
+
+/*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
+/*	XM_HT_THR	16 bit r/w	Host Request Threshold */
+/*	XM_RX_THR	16 bit r/w	Rx Request Threshold */
+								/* Bit 15..11	reserved */
+#define XM_THR_MSK		0x03ff	/* Bit 10.. 0	Rx/Tx Request Threshold bits */
+
+
+/*	XM_TX_STAT	32 bit r/o	Tx Status LIFO Register */
+#define XM_ST_VALID		(1UL<<31)	/* Bit 31:	Status Valid */
+#define XM_ST_BYTE_CNT	(0x3fffL<<17)	/* Bit 30..17:	Tx frame Length */
+#define XM_ST_RETRY_CNT	(0x1fL<<12)	/* Bit 16..12:	Retry Count */
+#define XM_ST_EX_COL	(1L<<11)	/* Bit 11:	Excessive Collisions */
+#define XM_ST_EX_DEF	(1L<<10)	/* Bit 10:	Excessive Deferral */
+#define XM_ST_BURST		(1L<<9)		/* Bit  9:	p. xmitted in burst md*/
+#define XM_ST_DEFER		(1L<<8)		/* Bit  8:	packet was defered */
+#define XM_ST_BC		(1L<<7)		/* Bit  7:	Broadcast packet */
+#define XM_ST_MC		(1L<<6)		/* Bit  6:	Multicast packet */
+#define XM_ST_UC		(1L<<5)		/* Bit  5:	Unicast packet */
+#define XM_ST_TX_UR		(1L<<4)		/* Bit  4:	FIFO Underrun occured */
+#define XM_ST_CS_ERR	(1L<<3)		/* Bit  3:	Carrier Sense Error */
+#define XM_ST_LAT_COL	(1L<<2)		/* Bit  2:	Late Collision Error */
+#define XM_ST_MUL_COL	(1L<<1)		/* Bit  1:	Multiple Collisions */
+#define XM_ST_SGN_COL	(1L<<0)		/* Bit  0:	Single Collision */
+
+/*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
+/*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
+									/* Bit 15..11:	reserved */
+#define XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
+
+
+/*	XM_DEV_ID	32 bit r/o	Device ID Register */
+#define XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit  7..5:	Chip Rev Num */
+
+
+/*	XM_MODE		32 bit r/w	Mode Register */
+									/* Bit 31..27:	reserved */
+#define XM_MD_ENA_REJ	(1L<<26)	/* Bit 26:	Enable Frame Reject */
+#define XM_MD_SPOE_E	(1L<<25)	/* Bit 25:	Send Pause on Edge */
+									/* 		extern generated */
+#define XM_MD_TX_REP	(1L<<24)	/* Bit 24:	Transmit Repeater Mode */
+#define XM_MD_SPOFF_I	(1L<<23)	/* Bit 23:	Send Pause on FIFO full */
+									/*		intern generated */
+#define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Little Endian */
+#define XM_MD_TX_CONT	(1L<<21)	/* Bit 21:	Send Continuous */
+#define XM_MD_TX_PAUSE	(1L<<20)	/* Bit 20: (sc)	Send Pause Frame */
+#define XM_MD_ATS		(1L<<19)	/* Bit 19:	Append Time Stamp */
+#define XM_MD_SPOL_I	(1L<<18)	/* Bit 18:	Send Pause on Low */
+									/*		intern generated */
+#define XM_MD_SPOH_I	(1L<<17)	/* Bit 17:	Send Pause on High */
+									/*		intern generated */
+#define XM_MD_CAP		(1L<<16)	/* Bit 16:	Check Address Pair */
+#define XM_MD_ENA_HASH	(1L<<15)	/* Bit 15:	Enable Hashing */
+#define XM_MD_CSA		(1L<<14)	/* Bit 14:	Check Station Address */
+#define XM_MD_CAA		(1L<<13)	/* Bit 13:	Check Address Array */
+#define XM_MD_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frame */
+#define XM_MD_RX_RUNT	(1L<<11)	/* Bit 11:	Rx Runt Frames */
+#define XM_MD_RX_IRLE	(1L<<10)	/* Bit 10:	Rx in Range Len Err Frame */
+#define XM_MD_RX_LONG	(1L<<9)		/* Bit  9:	Rx Long Frame */
+#define XM_MD_RX_CRCE	(1L<<8)		/* Bit  8:	Rx CRC Error Frame */
+#define XM_MD_RX_ERR	(1L<<7)		/* Bit  7:	Rx Error Frame */
+#define XM_MD_DIS_UC	(1L<<6)		/* Bit  6:	Disable Rx Unicast */
+#define XM_MD_DIS_MC	(1L<<5)		/* Bit  5:	Disable Rx Multicast */
+#define XM_MD_DIS_BC	(1L<<4)		/* Bit  4:	Disable Rx Broadcast */
+#define XM_MD_ENA_PROM	(1L<<3)		/* Bit  3:	Enable Promiscuous */
+#define XM_MD_ENA_BE	(1L<<2)		/* Bit  2:	Enable Big Endian */
+#define XM_MD_FTF		(1L<<1)		/* Bit  1: (sc)	Flush Tx FIFO */
+#define XM_MD_FRF		(1L<<0)		/* Bit  0: (sc)	Flush Rx FIFO */
+
+#define XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE		(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+				XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+
+/*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
+								/* Bit 16..6:	reserved */
+#define XM_SC_SNP_RXC	(1<<5)	/* Bit  5: (sc)	Snap Rx Counters */
+#define XM_SC_SNP_TXC	(1<<4)	/* Bit  4: (sc)	Snap Tx Counters */
+#define XM_SC_CP_RXC	(1<<3)	/* Bit  3: 	Copy Rx Counters Continuously */
+#define XM_SC_CP_TXC	(1<<2)	/* Bit  2:	Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC	(1<<1)	/* Bit  1: (sc)	Clear Rx Counters */
+#define XM_SC_CLR_TXC	(1<<0)	/* Bit  0: (sc) Clear Tx Counters */
+
+
+/*	XM_RX_CNT_EV	32 bit r/o	Rx Counter Event Register */
+/*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
+#define XMR_MAX_SZ_OV	(1UL<<31)	/* Bit 31:	1024-MaxSize Rx Cnt Ov*/
+#define XMR_1023B_OV	(1L<<30)	/* Bit 30:	512-1023Byte Rx Cnt Ov*/
+#define XMR_511B_OV		(1L<<29)	/* Bit 29:	256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV		(1L<<28)	/* Bit 28:	128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV		(1L<<27)	/* Bit 27:	65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV		(1L<<26)	/* Bit 26:	64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV		(1L<<25)	/* Bit 25:	Rx Util Cnt Overflow */
+#define XMR_UTIL_UR		(1L<<24)	/* Bit 24:	Rx Util Cnt Underrun */
+#define XMR_CEX_ERR_OV	(1L<<23)	/* Bit 23:	CEXT Err Cnt Ov */
+									/* Bit 22:	reserved */
+#define XMR_FCS_ERR_OV	(1L<<21)	/* Bit 21:	Rx FCS Error Cnt Ov */
+#define XMR_LNG_ERR_OV	(1L<<20)	/* Bit 20:	Rx too Long Err Cnt Ov*/
+#define XMR_RUNT_OV		(1L<<19)	/* Bit 19:	Runt Event Cnt Ov */
+#define XMR_SHT_ERR_OV	(1L<<18)	/* Bit 18:	Rx Short Ev Err Cnt Ov*/
+#define XMR_SYM_ERR_OV	(1L<<17)	/* Bit 17:	Rx Sym Err Cnt Ov */
+									/* Bit 16:	reserved */
+#define XMR_CAR_ERR_OV	(1L<<15)	/* Bit 15:	Rx Carr Ev Err Cnt Ov */
+#define XMR_JAB_PKT_OV	(1L<<14)	/* Bit 14:	Rx Jabb Packet Cnt Ov */
+#define XMR_FIFO_OV		(1L<<13)	/* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FRA_ERR_OV	(1L<<12)	/* Bit 12:	Rx Framing Err Cnt Ov */
+#define XMR_FMISS_OV	(1L<<11)	/* Bit 11:	Rx Missed Ev Cnt Ov */
+#define XMR_BURST		(1L<<10)	/* Bit 10:	Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC		(1L<<9)		/* Bit  9:	Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP		(1L<<8)		/* Bit  8:	Rx inv Pause Frame Ov */
+#define XMR_MCTRL_OV	(1L<<7)		/* Bit  7:	Rx MAC Ctrl-F Cnt Ov */
+#define XMR_MPAUSE_OV	(1L<<6)		/* Bit  6:	Rx Pause MAC Ctrl-F Ov*/
+#define XMR_UC_OK_OV	(1L<<5)		/* Bit  5:	Rx Unicast Frame CntOv*/
+#define XMR_MC_OK_OV	(1L<<4)		/* Bit  4:	Rx Multicast Cnt Ov */
+#define XMR_BC_OK_OV	(1L<<3)		/* Bit  3:	Rx Broadcast Cnt Ov */
+#define XMR_OK_LO_OV	(1L<<2)		/* Bit  2:	Octets Rx OK Low CntOv*/
+#define XMR_OK_HI_OV	(1L<<1)		/* Bit  1:	Octets Rx OK Hi Cnt Ov*/
+#define XMR_OK_OV		(1L<<0)		/* Bit  0:	Frames Received Ok Ov */
+
+#define XMR_DEF_MSK		(XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/*	XM_TX_CNT_EV	32 bit r/o	Tx Counter Event Register */
+/*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
+									/* Bit 31..26:	reserved */
+#define XMT_MAX_SZ_OV	(1L<<25)	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
+#define XMT_1023B_OV	(1L<<24)	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
+#define XMT_511B_OV		(1L<<23)	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV		(1L<<22)	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV		(1L<<21)	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV		(1L<<20)	/* Bit 20:	64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV		(1L<<19)	/* Bit 19:	Tx Util Cnt Overflow */
+#define XMT_UTIL_UR		(1L<<18)	/* Bit 18:	Tx Util Cnt Underrun */
+#define XMT_CS_ERR_OV	(1L<<17)	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
+#define XMT_FIFO_UR_OV	(1L<<16)	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
+#define XMT_EX_DEF_OV	(1L<<15)	/* Bit 15:	Tx Ex Deferall Cnt Ov */
+#define XMT_DEF			(1L<<14)	/* Bit 14:	Tx Deferred Cnt Ov */
+#define XMT_LAT_COL_OV	(1L<<13)	/* Bit 13:	Tx Late Col Cnt Ov */
+#define XMT_ABO_COL_OV	(1L<<12)	/* Bit 12:	Tx abo dueto Ex Col Ov*/
+#define XMT_MUL_COL_OV	(1L<<11)	/* Bit 11:	Tx Mult Col Cnt Ov */
+#define XMT_SNG_COL		(1L<<10)	/* Bit 10:	Tx Single Col Cnt Ov */
+#define XMT_MCTRL_OV	(1L<<9)		/* Bit  9:	Tx MAC Ctrl Counter Ov*/
+#define XMT_MPAUSE		(1L<<8)		/* Bit  8:	Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST		(1L<<7)		/* Bit  7:	Tx Burst Event Cnt Ov */
+#define XMT_LONG		(1L<<6)		/* Bit  6:	Tx Long Frame Cnt Ov */
+#define XMT_UC_OK_OV	(1L<<5)		/* Bit  5:	Tx Unicast Cnt Ov */
+#define XMT_MC_OK_OV	(1L<<4)		/* Bit  4:	Tx Multicast Cnt Ov */
+#define XMT_BC_OK_OV	(1L<<3)		/* Bit  3:	Tx Broadcast Cnt Ov */
+#define XMT_OK_LO_OV	(1L<<2)		/* Bit  2:	Octets Tx OK Low CntOv*/
+#define XMT_OK_HI_OV	(1L<<1)		/* Bit  1:	Octets Tx OK Hi Cnt Ov*/
+#define XMT_OK_OV		(1L<<0)		/* Bit  0:	Frames Tx Ok Ov */
+
+#define XMT_DEF_MSK		(XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+/*
+ * Receive Frame Status Encoding
+ */
+#define XMR_FS_LEN	(0x3fffUL<<18)	/* Bit 31..18:	Rx Frame Length */
+#define XMR_FS_2L_VLAN	(1L<<17)	/* Bit 17:	tagged wh 2Lev VLAN ID*/
+#define XMR_FS_1L_VLAN	(1L<<16)	/* Bit 16:	tagged wh 1Lev VLAN ID*/
+#define XMR_FS_BC		(1L<<15)	/* Bit 15:	Broadcast Frame */
+#define XMR_FS_MC		(1L<<14)	/* Bit 14:	Multicast Frame */
+#define XMR_FS_UC		(1L<<13)	/* Bit 13:	Unicast Frame */
+									/* Bit 12:	reserved */
+#define XMR_FS_BURST	(1L<<11)	/* Bit 11:	Burst Mode */
+#define XMR_FS_CEX_ERR	(1L<<10)	/* Bit 10:	Carrier Ext. Error */
+#define XMR_FS_802_3	(1L<<9)		/* Bit  9:	802.3 Frame */
+#define XMR_FS_COL_ERR	(1L<<8)		/* Bit  8:	Collision Error */
+#define XMR_FS_CAR_ERR	(1L<<7)		/* Bit  7:	Carrier Event Error */
+#define XMR_FS_LEN_ERR	(1L<<6)		/* Bit  6:	In-Range Length Error */
+#define XMR_FS_FRA_ERR	(1L<<5)		/* Bit  5:	Framing Error */
+#define XMR_FS_RUNT		(1L<<4)		/* Bit  4:	Runt Frame */
+#define XMR_FS_LNG_ERR	(1L<<3)		/* Bit  3:	Giant (Jumbo) Frame */
+#define XMR_FS_FCS_ERR	(1L<<2)		/* Bit  2:	Frame Check Sequ Err */
+#define XMR_FS_ERR		(1L<<1)		/* Bit  1:	Frame Error */
+#define XMR_FS_MCTRL	(1L<<0)		/* Bit  0:	MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *	XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *	XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+#define XMR_FS_ANY_ERR	XMR_FS_ERR
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+#define PHY_XMAC_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_XMAC_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define PHY_XMAC_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_XMAC_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_XMAC_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_XMAC_AUNE_LP	0x05	/* 16 bit r/o	Link Partner Abi Reg */
+#define PHY_XMAC_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_XMAC_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_XMAC_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
+	/* 0x09 - 0x0e:		reserved */
+#define PHY_XMAC_EXT_STAT	0x0f	/* 16 bit r/o	Ext Status Register */
+#define PHY_XMAC_RES_ABI	0x10	/* 16 bit r/o	PHY Resolved Ability */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_BCOM_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_BCOM_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_BCOM_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_BCOM_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_BCOM_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_BCOM_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_BCOM_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_BCOM_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_BCOM_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
+	/* Broadcom-specific registers */
+#define PHY_BCOM_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_BCOM_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define PHY_BCOM_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_BCOM_P_EXT_CTRL	0x10	/* 16 bit r/w	PHY Extended Ctrl Reg */
+#define PHY_BCOM_P_EXT_STAT	0x11	/* 16 bit r/o	PHY Extended Stat Reg */
+#define PHY_BCOM_RE_CTR		0x12	/* 16 bit r/w	Receive Error Counter */
+#define PHY_BCOM_FC_CTR		0x13	/* 16 bit r/w	False Carr Sense Cnt */
+#define PHY_BCOM_RNO_CTR	0x14	/* 16 bit r/w	Receiver NOT_OK Cnt */
+	/* 0x15 - 0x17:		reserved */
+#define PHY_BCOM_AUX_CTRL	0x18	/* 16 bit r/w	Auxiliary Control Reg */
+#define PHY_BCOM_AUX_STAT	0x19	/* 16 bit r/o	Auxiliary Stat Summary */
+#define PHY_BCOM_INT_STAT	0x1a	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_BCOM_INT_MASK	0x1b	/* 16 bit r/w	Interrupt Mask Reg */
+	/* 0x1c:		reserved */
+	/* 0x1d - 0x1f:		test registers */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+#define PHY_MARV_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_MARV_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_MARV_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_MARV_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_MARV_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_MARV_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_MARV_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_MARV_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_MARV_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
+	/* Marvel-specific registers */
+#define PHY_MARV_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_MARV_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define PHY_MARV_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_MARV_PHY_CTRL	0x10	/* 16 bit r/w	PHY Specific Ctrl Reg */
+#define PHY_MARV_PHY_STAT	0x11	/* 16 bit r/o	PHY Specific Stat Reg */
+#define PHY_MARV_INT_MASK	0x12	/* 16 bit r/w	Interrupt Mask Reg */
+#define PHY_MARV_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_MARV_EXT_CTRL	0x14	/* 16 bit r/w	Ext. PHY Specific Ctrl */
+#define PHY_MARV_RXE_CNT	0x15	/* 16 bit r/w	Receive Error Counter */
+#define PHY_MARV_EXT_ADR	0x16	/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	/* 0x17:		reserved */
+#define PHY_MARV_LED_CTRL	0x18	/* 16 bit r/w	LED Control Reg */
+#define PHY_MARV_LED_OVER	0x19	/* 16 bit r/w	Manual LED Override Reg */
+#define PHY_MARV_EXT_CTRL_2	0x1a	/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+#define PHY_MARV_EXT_P_STAT	0x1b	/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+#define PHY_MARV_CABLE_DIAG	0x1c	/* 16 bit r/o	Cable Diagnostic Reg */
+	/* 0x1d - 0x1f:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Level One-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_LONE_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_LONE_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_LONE_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_LONE_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_LONE_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_LONE_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_LONE_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_LONE_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_LONE_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner*/
+	/* Level One-specific registers */
+#define PHY_LONE_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg*/
+#define PHY_LONE_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define PHY_LONE_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_LONE_PORT_CFG	0x10	/* 16 bit r/w	Port Configuration Reg*/
+#define PHY_LONE_Q_STAT		0x11	/* 16 bit r/o	Quick Status Reg */
+#define PHY_LONE_INT_ENAB	0x12	/* 16 bit r/w	Interrupt Enable Reg */
+#define PHY_LONE_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_LONE_LED_CFG	0x14	/* 16 bit r/w	LED Configuration Reg */
+#define PHY_LONE_PORT_CTRL	0x15	/* 16 bit r/w	Port Control Reg */
+#define PHY_LONE_CIM		0x16	/* 16 bit r/o	CIM Reg */
+	/* 0x17 -0x1c:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * National-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_NAT_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_NAT_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define PHY_NAT_ID0			0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_NAT_ID1			0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_NAT_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_NAT_AUNE_LP		0x05	/* 16 bit r/o	Link Partner Ability Reg */
+#define PHY_NAT_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_NAT_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_NAT_NEPG_LP		0x08	/* 16 bit r/o	Next Page Link Partner Reg */
+	/* National-specific registers */
+#define PHY_NAT_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg */
+#define PHY_NAT_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define PHY_NAT_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Register */
+#define PHY_NAT_EXT_CTRL1	0x10	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT1		0x11	/* 16 bit r/o	Quick Status Reg1 */
+#define PHY_NAT_10B_OP		0x12	/* 16 bit r/o	10Base-T Operations Reg */
+#define PHY_NAT_EXT_CTRL2	0x13	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT2		0x14	/* 16 bit r/o	Quick Status Reg2 */
+	/* 0x15 -0x18:		reserved */
+#define PHY_NAT_PHY_ADDR	0x19	/* 16 bit r/o	PHY Address Register */
+
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * PHY bit definitions
+ * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are
+ * Xmac/Broadcom/LevelOne/National-specific.
+ * All other are general.
+ */
+
+/*****  PHY_XMAC_CTRL	16 bit r/w	PHY Control Register *****/
+/*****  PHY_BCOM_CTRL	16 bit r/w	PHY Control Register *****/
+/*****  PHY_LONE_CTRL	16 bit r/w	PHY Control Register *****/
+#define PHY_CT_RESET	(1<<15)	/* Bit 15: (sc)	clear all PHY related regs */
+#define PHY_CT_LOOP		(1<<14)	/* Bit 14:	enable Loopback over PHY */
+#define PHY_CT_SPS_LSB	(1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
+#define PHY_CT_ANE		(1<<12)	/* Bit 12:	Auto-Negotiation Enabled */
+#define PHY_CT_PDOWN	(1<<11)	/* Bit 11: (BC,L1) Power Down Mode */
+#define PHY_CT_ISOL		(1<<10)	/* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_RE_CFG	(1<<9)	/* Bit  9: (sc) Restart Auto-Negotiation */
+#define PHY_CT_DUP_MD	(1<<8)	/* Bit  8:	Duplex Mode */
+#define PHY_CT_COL_TST	(1<<7)	/* Bit  7: (BC,L1) Collision Test enabled */
+#define PHY_CT_SPS_MSB	(1<<6)	/* Bit  6: (BC,L1) Speed select, upper bit */
+								/* Bit  5..0:	reserved */
+
+#define PHY_CT_SP1000	PHY_CT_SPS_MSB	/* enable speed of 1000 Mbps */
+#define PHY_CT_SP100	PHY_CT_SPS_LSB	/* enable speed of  100 Mbps */
+#define PHY_CT_SP10		(0)				/* enable speed of   10 Mbps */
+
+
+/*****  PHY_XMAC_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_BCOM_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_MARV_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_LONE_STAT	16 bit r/w	PHY Status Register *****/
+								/* Bit 15..9:	reserved */
+				/*	(BC/L1) 100/10 Mbps cap bits ignored*/
+#define PHY_ST_EXT_ST	(1<<8)	/* Bit  8:	Extended Status Present */
+								/* Bit  7:	reserved */
+#define PHY_ST_PRE_SUP	(1<<6)	/* Bit  6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER	(1<<5)	/* Bit  5:	Auto-Negotiation Over */
+#define PHY_ST_REM_FLT	(1<<4)	/* Bit  4:	Remote Fault Condition Occured */
+#define PHY_ST_AN_CAP	(1<<3)	/* Bit  3:	Auto-Negotiation Capability */
+#define PHY_ST_LSYNC	(1<<2)	/* Bit  2:	Link Synchronized */
+#define PHY_ST_JAB_DET	(1<<1)	/* Bit  1: (BC/L1) Jabber Detected */
+#define PHY_ST_EXT_REG	(1<<0)	/* Bit  0:	Extended Register available */
+
+
+/*****	PHY_XMAC_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_BCOM_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_MARV_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_LONE_ID1		16 bit r/o	PHY ID1 Register */
+#define PHY_I1_OUI_MSK	(0x3f<<10)	/* Bit 15..10:	Organization Unique ID */
+#define PHY_I1_MOD_NUM	(0x3f<<4)	/* Bit  9.. 4:	Model Number */
+#define PHY_I1_REV_MSK	0x0f		/* Bit  3.. 0:	Revision Number */
+
+/* different Broadcom PHY Ids */
+#define PHY_BCOM_ID1_A1		0x6041
+#define PHY_BCOM_ID1_B2		0x6043
+#define PHY_BCOM_ID1_C0		0x6044
+#define PHY_BCOM_ID1_C5		0x6047
+
+
+/*****  PHY_XMAC_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_XMAC_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+#define PHY_AN_NXT_PG	(1<<15)	/* Bit 15:	Request Next Page */
+#define PHY_X_AN_ACK	(1<<14)	/* Bit 14: (ro)	Acknowledge Received */
+#define PHY_X_AN_RFB	(3<<12)	/* Bit 13..12:	Remote Fault Bits */
+								/* Bit 11.. 9:	reserved */
+#define PHY_X_AN_PAUSE	(3<<7)	/* Bit  8.. 7:	Pause Bits */
+#define PHY_X_AN_HD		(1<<6)	/* Bit  6:	Half Duplex */
+#define PHY_X_AN_FD		(1<<5)	/* Bit  5:	Full Duplex */
+								/* Bit  4.. 0:	reserved */
+
+/*****  PHY_BCOM_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_BCOM_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_B_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric Pause */
+#define PHY_B_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****  PHY_LONE_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_LONE_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_L_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric Pause */
+#define PHY_L_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****  PHY_NAT_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_NAT_AUNE_LP		16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_N_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_N_AN_100F	(1<<11)	/* Bit 11:	100Base-T2 FD Support */
+#define PHY_N_AN_100H	(1<<10)	/* Bit 10:	100Base-T2 HD Support */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/* field type definition for PHY_x_AN_SEL */
+#define PHY_SEL_TYPE	0x01	/* 00001 = Ethernet */
+
+/*****  PHY_XMAC_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+								/* Bit 15..4:	reserved */
+#define PHY_AN_LP_NP	(1<<3)	/* Bit  3:	Link Partner can Next Page */
+#define PHY_AN_LOC_NP	(1<<2)	/* Bit  2:	Local PHY can Next Page */
+#define PHY_AN_RX_PG	(1<<1)	/* Bit  1:	Page Received */
+								/* Bit  0:	reserved */
+
+/*****  PHY_BCOM_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+								/* Bit 15..5:	reserved */
+#define PHY_B_AN_PDF	(1<<4)	/* Bit  4:	Parallel Detection Fault */
+/*	PHY_AN_LP_NP		(see XMAC) Bit  3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP		(see XMAC) Bit  2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG		(see XMAC) Bit  1:	Page Received */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit  0:	Link Partner Auto-Neg. Cap. */
+
+/*****  PHY_LONE_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+#define PHY_L_AN_BP		(1<<5)	/* Bit  5:	Base Page Indication */
+#define PHY_L_AN_PDF	(1<<4)	/* Bit  4:	Parallel Detection Fault */
+/*	PHY_AN_LP_NP		(see XMAC) Bit  3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP		(see XMAC) Bit  2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG		(see XMAC) Bit  1:	Page Received */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit  0:	Link Partner Auto-Neg. Cap. */
+
+
+/*****  PHY_XMAC_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_BCOM_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_LONE_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_XMAC_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_BCOM_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_LONE_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+#define PHY_NP_MORE		(1<<15)	/* Bit 15:	More, Next Pages to follow */
+#define PHY_NP_ACK1		(1<<14)	/* Bit 14: (ro)	Ack 1, for receiving a message*/
+#define PHY_NP_MSG_VAL	(1<<13)	/* Bit 13:	Message Page valid */
+#define PHY_NP_ACK2		(1<<12)	/* Bit 12:	Ack 2, comply with msg content*/
+#define PHY_NP_TOG		(1<<11)	/* Bit 11:	Toggle Bit, ensure sync */
+#define PHY_NP_MSG		0x07ff	/* Bit 10..0:	Message from/to Link Partner */
+
+/*
+ * XMAC-Specific
+ */
+/*****  PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
+#define PHY_X_EX_FD		(1<<15)	/* Bit 15:	Device Supports Full Duplex */
+#define PHY_X_EX_HD		(1<<14)	/* Bit 14:	Device Supports Half Duplex */
+								/* Bit 13..0:	reserved */
+
+/*****  PHY_XMAC_RES_ABI	16 bit r/o	PHY Resolved Ability *****/
+								/* Bit 15..9:	reserved */
+#define PHY_X_RS_PAUSE	(3<<7)	/* Bit  8..7:	selected Pause Mode */
+#define PHY_X_RS_HD		(1<<6)	/* Bit  6:	Half Duplex Mode selected */
+#define PHY_X_RS_FD		(1<<5)	/* Bit  5:	Full Duplex Mode selected */
+#define PHY_X_RS_ABLMIS (1<<4)	/* Bit  4:	duplex or pause cap mismatch */
+#define PHY_X_RS_PAUMIS (1<<3)	/* Bit  3:	pause capability missmatch */
+								/* Bit  2..0:	reserved */
+/*
+ * Remote Fault Bits (PHY_X_AN_RFB) encoding
+ */
+#define X_RFB_OK		(0<<12)	/* Bit 13..12	No errors, Link OK */
+#define X_RFB_LF		(1<<12)	/* Bit 13..12	Link Failure */
+#define X_RFB_OFF		(2<<12)	/* Bit 13..12	Offline */
+#define X_RFB_AN_ERR	(3<<12)	/* Bit 13..12	Auto-Negotiation Error */
+
+/*
+ * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
+ */
+#define PHY_X_P_NO_PAUSE	(0<<7)	/* Bit  8..7:	no Pause Mode */
+#define PHY_X_P_SYM_MD		(1<<7)	/* Bit  8..7:	symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD		(2<<7)	/* Bit  8..7:	asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD		(3<<7)	/* Bit  8..7:	both Pause Mode */
+
+
+/*
+ * Broadcom-Specific
+ */
+/*****  PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_B_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_B_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_B_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_B_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_B_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_B_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_B_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_B_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status */
+#define PHY_B_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_B_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_BCOM_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_B_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_B_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_B_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_B_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/*****  PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+#define PHY_B_PEC_MAC_PHY	(1<<15)	/* Bit 15:	10BIT/GMI-Interface */
+#define PHY_B_PEC_DIS_CROSS	(1<<14)	/* Bit 14:	Disable MDI Crossover */
+#define PHY_B_PEC_TX_DIS	(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_B_PEC_INT_DIS	(1<<12)	/* Bit 12:	Interrupts Disabled */
+#define PHY_B_PEC_F_INT		(1<<11)	/* Bit 11:	Force Interrupt */
+#define PHY_B_PEC_BY_45		(1<<10)	/* Bit 10:	Bypass 4B5B-Decoder */
+#define PHY_B_PEC_BY_SCR	(1<<9)	/* Bit  9:	Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3	(1<<8)	/* Bit  8:	Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA	(1<<7)	/* Bit  7:	Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR	(1<<6)	/* Bit  6:	Reset Scrambler */
+#define PHY_B_PEC_EN_LTR	(1<<5)	/* Bit  5:	Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON	(1<<4)	/* Bit  4:	Force LED's on */
+#define PHY_B_PEC_LED_OFF	(1<<3)	/* Bit  3:	Force LED's off */
+#define PHY_B_PEC_EX_IPG	(1<<2)	/* Bit  2:	Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED		(1<<1)	/* Bit  1:	Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA	(1<<0)	/* Bit  0:	GMII FIFO Elasticy */
+
+/*****  PHY_BCOM_P_EXT_STAT	16 bit r/o	PHY Extended Status Reg *****/
+									/* Bit 15..14:	reserved */
+#define PHY_B_PES_CROSS_STAT	(1<<13)	/* Bit 13:	MDI Crossover Status */
+#define PHY_B_PES_INT_STAT	(1<<12)	/* Bit 12:	Interrupt Status */
+#define PHY_B_PES_RRS		(1<<11)	/* Bit 11:	Remote Receiver Stat. */
+#define PHY_B_PES_LRS		(1<<10)	/* Bit 10:	Local Receiver Stat. */
+#define PHY_B_PES_LOCKED	(1<<9)	/* Bit  9:	Locked */
+#define PHY_B_PES_LS		(1<<8)	/* Bit  8:	Link Status */
+#define PHY_B_PES_RF		(1<<7)	/* Bit  7:	Remote Fault */
+#define PHY_B_PES_CE_ER		(1<<6)	/* Bit  6:	Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD	(1<<5)	/* Bit  5:	Bad SSD */
+#define PHY_B_PES_BAD_ESD	(1<<4)	/* Bit  4:	Bad ESD */
+#define PHY_B_PES_RX_ER		(1<<3)	/* Bit  3:	Receive Error */
+#define PHY_B_PES_TX_ER		(1<<2)	/* Bit  2:	Transmit Error */
+#define PHY_B_PES_LOCK_ER	(1<<1)	/* Bit  1:	Lock Error */
+#define PHY_B_PES_MLT3_ER	(1<<0)	/* Bit  0:	MLT3 code Error */
+
+/*****  PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
+									/* Bit 15..8:	reserved */
+#define PHY_B_FC_CTR		0xff	/* Bit  7..0:	False Carrier Counter */
+
+/*****  PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC_MSK	0xff00	/* Bit 15..8:	Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM_MSK	0x00ff	/* Bit  7..0:	Remote Rx NOT_OK cnt */
+
+/*****  PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+#define PHY_B_AC_L_SQE		(1<<15)	/* Bit 15:	Low Squelch */
+#define PHY_B_AC_LONG_PACK	(1<<14)	/* Bit 14:	Rx Long Packets */
+#define PHY_B_AC_ER_CTRL	(3<<12)	/* Bit 13..12:	Edgerate Control */
+									/* Bit 11:	reserved */
+#define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	Tx test bit, always 1 */
+									/* Bit  9.. 8:	reserved */
+#define PHY_B_AC_DIS_PRF	(1<<7)	/* Bit  7:	dis part resp filter */
+									/* Bit  6:	reserved */
+#define PHY_B_AC_DIS_PM		(1<<5)	/* Bit  5:	dis power management */
+									/* Bit  4:	reserved */
+#define PHY_B_AC_DIAG		(1<<3)	/* Bit  3:	Diagnostic Mode */
+									/* Bit  2.. 0:	reserved */
+
+/*****  PHY_BCOM_AUX_STAT	16 bit r/o	Auxiliary Status Reg *****/
+#define PHY_B_AS_AN_C		(1<<15)	/* Bit 15:	AutoNeg complete */
+#define PHY_B_AS_AN_CA		(1<<14)	/* Bit 14:	AN Complete Ack */
+#define PHY_B_AS_ANACK_D	(1<<13)	/* Bit 13:	AN Ack Detect */
+#define PHY_B_AS_ANAB_D		(1<<12)	/* Bit 12:	AN Ability Detect */
+#define PHY_B_AS_NPW		(1<<11)	/* Bit 11:	AN Next Page Wait */
+#define PHY_B_AS_AN_RES_MSK	(7<<8)	/* Bit 10..8:	AN HDC */
+#define PHY_B_AS_PDF		(1<<7)	/* Bit  7:	Parallel Detect. Fault */
+#define PHY_B_AS_RF			(1<<6)	/* Bit  6:	Remote Fault */
+#define PHY_B_AS_ANP_R		(1<<5)	/* Bit  5:	AN Page Received */
+#define PHY_B_AS_LP_ANAB	(1<<4)	/* Bit  4:	LP AN Ability */
+#define PHY_B_AS_LP_NPAB	(1<<3)	/* Bit  3:	LP Next Page Ability */
+#define PHY_B_AS_LS			(1<<2)	/* Bit  2:	Link Status */
+#define PHY_B_AS_PRR		(1<<1)	/* Bit  1:	Pause Resolution-Rx */
+#define PHY_B_AS_PRT		(1<<0)	/* Bit  0:	Pause Resolution-Tx */
+
+#define PHY_B_AS_PAUSE_MSK	(PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+									/* Bit 15:	reserved */
+#define PHY_B_IS_PSE		(1<<14)	/* Bit 14:	Pair Swap Error */
+#define PHY_B_IS_MDXI_SC	(1<<13)	/* Bit 13:	MDIX Status Change */
+#define PHY_B_IS_HCT		(1<<12)	/* Bit 12:	counter above 32k */
+#define PHY_B_IS_LCT		(1<<11)	/* Bit 11:	counter above 128 */
+#define PHY_B_IS_AN_PR		(1<<10)	/* Bit 10:	Page Received */
+#define PHY_B_IS_NO_HDCL	(1<<9)	/* Bit  9:	No HCD Link */
+#define PHY_B_IS_NO_HDC		(1<<8)	/* Bit  8:	No HCD */
+#define PHY_B_IS_NEG_USHDC	(1<<7)	/* Bit  7:	Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER	(1<<6)	/* Bit  6:	Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE	(1<<5)	/* Bit  5:	Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE	(1<<4)	/* Bit  4:	Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE	(1<<3)	/* Bit  3:	Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE	(1<<2)	/* Bit  2:	Link Speed Change */
+#define PHY_B_IS_LST_CHANGE	(1<<1)	/* Bit  1:	Link Status Changed */
+#define PHY_B_IS_CRC_ER		(1<<0)	/* Bit  0:	CRC Error */
+
+#define PHY_B_DEF_MSK	(~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+#define PHY_B_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_B_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
+
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+#define PHY_B_RES_1000FD	(7<<8)	/* Bit 10..8:	1000Base-T Full Dup. */
+#define PHY_B_RES_1000HD	(6<<8)	/* Bit 10..8:	1000Base-T Half Dup. */
+/* others: 100/10: invalid for us */
+
+/*
+ * Level One-Specific
+ */
+/*****  PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_L_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_L_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_L_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_L_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_L_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_LONE_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_L_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_L_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_L_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status*/
+#define PHY_L_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_L_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_LONE_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_L_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_L_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_L_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_L_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/*****  PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
+#define PHY_L_PC_REP_MODE	(1<<15)	/* Bit 15:	Repeater Mode */
+									/* Bit 14:	reserved */
+#define PHY_L_PC_TX_DIS		(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_L_PC_BY_SCR		(1<<12)	/* Bit 12:	Bypass Scrambler */
+#define PHY_L_PC_BY_45		(1<<11)	/* Bit 11:	Bypass 4B5B-Decoder */
+#define PHY_L_PC_JAB_DIS	(1<<10)	/* Bit 10:	Jabber Disabled */
+#define PHY_L_PC_SQE		(1<<9)	/* Bit  9:	Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP	(1<<8)	/* Bit  8:	TP Loopback */
+#define PHY_L_PC_SSS		(1<<7)	/* Bit  7:	Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE	(1<<6)	/* Bit  6:	FIFO Size */
+#define PHY_L_PC_PRE_EN		(1<<5)	/* Bit  5:	Preamble Enable */
+#define PHY_L_PC_CIM		(1<<4)	/* Bit  4:	Carrier Integrity Mon */
+#define PHY_L_PC_10_SER		(1<<3)	/* Bit  3:	Use Serial Output */
+#define PHY_L_PC_ANISOL		(1<<2)	/* Bit  2:	Unisolate Port */
+#define PHY_L_PC_TEN_BIT	(1<<1)	/* Bit  1:	10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK	(1<<0)	/* Bit  0: (ro)	ALTCLOCK Mode on */
+
+/*****  PHY_LONE_Q_STAT		16 bit r/o	Quick Status Reg *****/
+#define PHY_L_QS_D_RATE		(3<<14)	/* Bit 15..14:	Data Rate */
+#define PHY_L_QS_TX_STAT	(1<<13)	/* Bit 13:	Transmitting */
+#define PHY_L_QS_RX_STAT	(1<<12)	/* Bit 12:	Receiving */
+#define PHY_L_QS_COL_STAT	(1<<11)	/* Bit 11:	Collision */
+#define PHY_L_QS_L_STAT		(1<<10)	/* Bit 10:	Link is up */
+#define PHY_L_QS_DUP_MOD	(1<<9)	/* Bit  9:	Full/Half Duplex */
+#define PHY_L_QS_AN			(1<<8)	/* Bit  8:	AutoNeg is On */
+#define PHY_L_QS_AN_C		(1<<7)	/* Bit  7:	AN is Complete */
+#define PHY_L_QS_LLE		(7<<4)	/* Bit  6:	Line Length Estim. */
+#define PHY_L_QS_PAUSE		(1<<3)	/* Bit  3:	LP advertised Pause */
+#define PHY_L_QS_AS_PAUSE	(1<<2)	/* Bit  2:	LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE	(1<<1)	/* Bit  1:	CIM Isolated */
+#define PHY_L_QS_EVENT		(1<<0)	/* Bit  0:	Event has occurred */
+
+/*****  PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
+/*****  PHY_LONE_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+									/* Bit 15..14:	reserved */
+#define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Auto-Negotiation fault */
+									/* Bit 12:	not described */
+#define PHY_L_IS_CROSS		(1<<11)	/* Bit 11:	Crossover used */
+#define PHY_L_IS_POL		(1<<10)	/* Bit 10:	Polarity correct. used*/
+#define PHY_L_IS_SS			(1<<9)	/* Bit  9:	Smart Speed Downgrade*/
+#define PHY_L_IS_CFULL		(1<<8)	/* Bit  8:	Counter Full */
+#define PHY_L_IS_AN_C		(1<<7)	/* Bit  7:	AutoNeg Complete */
+#define PHY_L_IS_SPEED		(1<<6)	/* Bit  6:	Speed Changed */
+#define PHY_L_IS_DUP		(1<<5)	/* Bit  5:	Duplex Changed */
+#define PHY_L_IS_LS			(1<<4)	/* Bit  4:	Link Status Changed */
+#define PHY_L_IS_ISOL		(1<<3)	/* Bit  3:	Isolate Occured */
+#define PHY_L_IS_MDINT		(1<<2)	/* Bit  2: (ro)	STAT: MII Int Pending */
+#define PHY_L_IS_INTEN		(1<<1)	/* Bit  1:	ENAB: Enable IRQs */
+#define PHY_L_IS_FORCE		(1<<0)	/* Bit  0:	ENAB: Force Interrupt */
+
+/* int. mask */
+#define PHY_L_DEF_MSK		(PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
+
+/*****  PHY_LONE_LED_CFG	16 bit r/w	LED Configuration Reg *****/
+#define PHY_L_LC_LEDC		(3<<14)	/* Bit 15..14:	Col/Blink/On/Off */
+#define PHY_L_LC_LEDR		(3<<12)	/* Bit 13..12:	Rx/Blink/On/Off */
+#define PHY_L_LC_LEDT		(3<<10)	/* Bit 11..10:	Tx/Blink/On/Off */
+#define PHY_L_LC_LEDG		(3<<8)	/* Bit  9..8:	Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS		(3<<6)	/* Bit  7..6:	10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL		(3<<4)	/* Bit  5..4:	Link/Blink/On/Off */
+#define PHY_L_LC_LEDF		(3<<2)	/* Bit  3..2:	Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH	(1<<1)	/* Bit  1:	Strech LED Pulses */
+#define PHY_L_LC_FREQ		(1<<0)	/* Bit  0:	30/100 ms */
+
+/*****  PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
+#define PHY_L_PC_TX_TCLK	(1<<15)	/* Bit 15:	Enable TX_TCLK */
+									/* Bit 14:	reserved */
+#define PHY_L_PC_ALT_NP		(1<<13)	/* Bit 14:	Alternate Next Page */
+#define PHY_L_PC_GMII_ALT	(1<<12)	/* Bit 13:	Alternate GMII driver */
+									/* Bit 11:	reserved */
+#define PHY_L_PC_TEN_CRS	(1<<10)	/* Bit 10:	Extend CRS*/
+									/* Bit  9..0:	not described */
+
+/*****  PHY_LONE_CIM		16 bit r/o	CIM Reg *****/
+#define PHY_L_CIM_ISOL		(255<<8)/* Bit 15..8:	Isolate Count */
+#define PHY_L_CIM_FALSE_CAR	(255<<0)/* Bit  7..0:	False Carrier Count */
+
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+#define PHY_L_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_L_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
+
+
+/*
+ * National-Specific
+ */
+/*****  PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_N_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_N_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_N_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_N_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_N_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+#define PHY_N_1000C_APC		(1<<7)	/* Bit  7:	Asymmetric Pause Cap. */
+									/* Bit  6..0:	reserved */
+
+/*****  PHY_NAT_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_N_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_N_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_N_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status*/
+#define PHY_N_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_N_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+#define PHY_N_1000C_LP_APC	(1<<9)	/* Bit  9:	LP Asym. Pause Cap. */
+									/* Bit  8:	reserved */
+#define PHY_N_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_NAT_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_N_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_N_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_N_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_N_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/* todo: those are still missing */
+/*****  PHY_NAT_EXT_CTRL1	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT1		16 bit r/o	Quick Status Reg1 *****/
+/*****  PHY_NAT_10B_OP		16 bit r/o	10Base-T Operations Reg *****/
+/*****  PHY_NAT_EXT_CTRL2	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT2		16 bit r/o	Quick Status Reg2 *****/
+/*****  PHY_NAT_PHY_ADDR	16 bit r/o	PHY Address Register *****/
+
+/*
+ * Marvell-Specific
+ */
+/*****  PHY_MARV_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_MARV_AUNE_LP	16 bit r/w	Link Part Ability Reg *****/
+#define PHY_M_AN_NXT_PG		BIT_15	/* Request Next Page */
+#define PHY_M_AN_ACK		BIT_14	/* (ro)	Acknowledge Received */
+#define PHY_M_AN_RF			BIT_13	/* Remote Fault */
+									/* Bit 12:	reserved */
+#define PHY_M_AN_ASP		BIT_11	/* Asymmetric Pause */
+#define PHY_M_AN_PC			BIT_10	/* MAC Pause implemented */
+#define PHY_M_AN_100_FD		BIT_8	/* Advertise 100Base-TX Full Duplex */
+#define PHY_M_AN_100_HD		BIT_7	/* Advertise 100Base-TX Half Duplex */
+#define PHY_M_AN_10_FD		BIT_6	/* Advertise 10Base-TX Full Duplex */
+#define PHY_M_AN_10_HD		BIT_5	/* Advertise 10Base-TX Half Duplex */
+
+/* special defines for FIBER (88E1011S only) */
+#define PHY_M_AN_ASP_X		BIT_8	/* Asymmetric Pause */
+#define PHY_M_AN_PC_X		BIT_7	/* MAC Pause implemented */
+#define PHY_M_AN_1000X_AHD	BIT_6	/* Advertise 10000Base-X Half Duplex */
+#define PHY_M_AN_1000X_AFD	BIT_5	/* Advertise 10000Base-X Full Duplex */
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+#define PHY_M_P_NO_PAUSE_X	(0<<7)	/* Bit  8.. 7:	no Pause Mode */
+#define PHY_M_P_SYM_MD_X	(1<<7)	/* Bit  8.. 7:	symmetric Pause Mode */
+#define PHY_M_P_ASYM_MD_X	(2<<7)	/* Bit  8.. 7:	asymmetric Pause Mode */
+#define PHY_M_P_BOTH_MD_X	(3<<7)	/* Bit  8.. 7:	both Pause Mode */
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_M_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_M_1000C_MSE		(1<<12)	/* Bit 12:	Manual Master/Slave Enable */
+#define PHY_M_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration (1=Master) */
+#define PHY_M_1000C_MPD		(1<<10)	/* Bit 10:	Multi-Port Device */
+#define PHY_M_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_M_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+
+#define PHY_M_PC_TX_FFD_MSK	(3<<14)	/* Bit 15..14:	Tx FIFO Depth Mask */
+#define PHY_M_PC_RX_FFD_MSK	(3<<12)	/* Bit 13..12:	Rx FIFO Depth Mask */
+#define PHY_M_PC_ASS_CRS_TX	(1<<11)	/* Bit 11:	Assert CRS on Transmit */
+#define PHY_M_PC_FL_GOOD	(1<<10)	/* Bit 10:	Force Link Good */
+#define PHY_M_PC_EN_DET_MSK	(3<<8)	/* Bit  9.. 8:	Energy Detect Mask */
+#define PHY_M_PC_ENA_EXT_D	(1<<7)	/* Bit  7:	Enable Ext. Distance (10BT) */
+#define PHY_M_PC_MDIX_MSK	(3<<5)	/* Bit  6.. 5:	MDI/MDIX Config. Mask */
+#define PHY_M_PC_DIS_125CLK	(1<<4)	/* Bit  4:	Disable 125 CLK */
+#define PHY_M_PC_MAC_POW_UP	(1<<3)	/* Bit  3:	MAC Power up */
+#define PHY_M_PC_SQE_T_ENA	(1<<2)	/* Bit  2:	SQE Test Enabled */
+#define PHY_M_PC_POL_R_DIS	(1<<1)	/* Bit  1:	Polarity Reversal Disabled */
+#define PHY_M_PC_DIS_JABBER	(1<<0)	/* Bit  0:	Disable Jabber */
+
+#define PHY_M_PC_MDI_XMODE(x)	SHIFT5(x)
+#define PHY_M_PC_MAN_MDI	0    	/* 00 = Manual MDI configuration */
+#define PHY_M_PC_MAN_MDIX	1		/* 01 = Manual MDIX configuration */
+#define PHY_M_PC_ENA_AUTO	3		/* 11 = Enable Automatic Crossover */
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+#define PHY_M_PS_SPEED_MSK	(3<<14)	/* Bit 15..14:	Speed Mask */
+#define PHY_M_PS_SPEED_1000	(1<<15)	/*       10 = 1000 Mbps */
+#define PHY_M_PS_SPEED_100	(1<<14)	/*       01 =  100 Mbps */
+#define PHY_M_PS_SPEED_10	0		/*       00 =   10 Mbps */
+#define PHY_M_PS_FULL_DUP	(1<<13)	/* Bit 13:	Full Duplex */
+#define PHY_M_PS_PAGE_REC	(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_PS_SPDUP_RES	(1<<11)	/* Bit 11:	Speed & Duplex Resolved */
+#define PHY_M_PS_LINK_UP	(1<<10)	/* Bit 10:	Link Up */
+#define PHY_M_PS_CABLE_MSK	(3<<7)	/* Bit  9.. 7:	Cable Length Mask */
+#define PHY_M_PS_MDI_X_STAT	(1<<6)	/* Bit  6:	MDI Crossover Stat (1=MDIX) */
+#define PHY_M_PS_DOWNS_STAT	(1<<5)	/* Bit  5:	Downshift Status (1=downsh.) */
+#define PHY_M_PS_ENDET_STAT	(1<<4)	/* Bit  4:	Energy Detect Status (1=act) */
+#define PHY_M_PS_TX_P_EN	(1<<3)	/* Bit  3:	Tx Pause Enabled */
+#define PHY_M_PS_RX_P_EN	(1<<2)	/* Bit  2:	Rx Pause Enabled */
+#define PHY_M_PS_POL_REV	(1<<1)	/* Bit  1:	Polarity Reversed */
+#define PHY_M_PC_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/*****  PHY_MARV_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+/*****  PHY_MARV_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+#define PHY_M_IS_AN_ERROR	(1<<15)	/* Bit 15:	Auto-Negotiation Error */
+#define PHY_M_IS_LSP_CHANGE	(1<<14)	/* Bit 14:	Link Speed Changed */
+#define PHY_M_IS_DUP_CHANGE	(1<<13)	/* Bit 13:	Duplex Mode Changed */
+#define PHY_M_IS_AN_PR		(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_IS_AN_COMPL	(1<<11)	/* Bit 11:	Auto-Negotiation Completed */
+#define PHY_M_IS_LST_CHANGE	(1<<10)	/* Bit 10:	Link Status Changed */
+#define PHY_M_IS_SYMB_ERROR	(1<<9)	/* Bit  9:	Symbol Error */
+#define PHY_M_IS_FALSE_CARR	(1<<8)	/* Bit  8:	False Carrier */
+#define PHY_M_IS_FIFO_ERROR	(1<<7)	/* Bit  7:	FIFO Overflow/Underrun Error */
+#define PHY_M_IS_MDI_CHANGE	(1<<6)	/* Bit  6:	MDI Crossover Changed */
+#define PHY_M_IS_DOWNSH_DET	(1<<5)	/* Bit  5:	Downshift Detected */
+#define PHY_M_IS_END_CHANGE	(1<<4)	/* Bit  4:	Energy Detect Changed */
+									/* Bit  3..2:	reserved */
+#define PHY_M_IS_POL_CHANGE	(1<<1)	/* Bit  1:	Polarity Changed */
+#define PHY_M_IS_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_DEF_MSK		(PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \
+							PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+#define PHY_M_EC_M_DSC_MSK	(3<<10)	/* Bit 11..10:	Master downshift counter */
+#define PHY_M_EC_S_DSC_MSK	(3<<8)	/* Bit  9.. 8:	Slave  downshift counter */
+#define PHY_M_EC_MAC_S_MSK	(7<<4)	/* Bit  6.. 4:	Def. MAC interface speed */
+
+#define PHY_M_EC_M_DSC(x)		SHIFT10(x)	/* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)		SHIFT8(x)	/* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)		SHIFT4(x)	/* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define MAC_TX_CLK_0_MHZ	2
+#define MAC_TX_CLK_2_5_MHZ	6
+#define MAC_TX_CLK_25_MHZ	7
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+#define PHY_M_LEDC_DIS_LED	(1<<15)	/* Bit 15:	Disable LED */
+#define PHY_M_LEDC_PULS_MSK	(7<<12)	/* Bit 14..12:  Pulse Stretch Mask */
+#define PHY_M_LEDC_F_INT	(1<<11)	/* Bit 11:	Force Interrupt */
+#define PHY_M_LEDC_BL_R_MSK	(7<<8)	/* Bit 10.. 8:  Blink Rate Mask */
+									/* Bit  7.. 5:	reserved */
+#define PHY_M_LEDC_LINK_MSK	(3<<3)	/* Bit  4.. 3:	Link Control Mask */
+#define PHY_M_LEDC_DP_CTRL	(1<<2)	/* Bit  2:	Duplex Control */
+#define PHY_M_LEDC_RX_CTRL	(1<<1)	/* Bit  1:	Rx activity / Link */
+#define PHY_M_LEDC_TX_CTRL	(1<<0)	/* Bit  0:	Tx activity / Link */
+
+#define PHY_M_LED_PULS_DUR(x)	SHIFT12(x)	/* Pulse Stretch Duration */
+
+#define	PULS_NO_STR		0		/* no pulse stretching */
+#define	PULS_21MS		1		/* 21 ms to 42 ms */
+#define PULS_42MS		2		/* 42 ms to 84 ms */
+#define PULS_84MS		3		/* 84 ms to 170 ms */
+#define PULS_170MS		4		/* 170 ms to 340 ms */
+#define PULS_340MS		5		/* 340 ms to 670 ms */
+#define PULS_670MS		6		/* 670 ms to 1.3 s */
+#define PULS_1300MS		7		/* 1.3 s to 2.7 s */
+
+#define PHY_M_LED_BLINK_RT(x)	SHIFT8(x)	/* Blink Rate */
+
+#define BLINK_42MS		0		/* 42 ms */
+#define BLINK_84MS		1		/* 84 ms */
+#define BLINK_170MS		2		/* 170 ms */
+#define BLINK_340MS		3		/* 340 ms */
+#define BLINK_670MS		4		/* 670 ms */
+								/* values 5 - 7: reserved */
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_DUP(x)		SHIFT10(x)	/* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)		SHIFT8(x)	/* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)		SHIFT6(x)	/* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	SHIFT4(x)	/* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)		SHIFT2(x)	/* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)		SHIFT0(x)	/* Bit  1.. 0:  Tx */
+
+#define MO_LED_NORM			0
+#define MO_LED_BLINK		1
+#define MO_LED_OFF			2
+#define MO_LED_ON			3
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+									/* Bit 15.. 7:	reserved */
+#define PHY_M_EC2_FI_IMPED	(1<<6)	/* Bit  6:	Fiber Input  Impedance */
+#define PHY_M_EC2_FO_IMPED	(1<<5)	/* Bit  5:	Fiber Output Impedance */
+#define PHY_M_EC2_FO_M_CLK	(1<<4)	/* Bit  4:	Fiber Mode Clock Enable */
+#define PHY_M_EC2_FO_BOOST	(1<<3)	/* Bit  3:	Fiber Output Boost */
+#define PHY_M_EC2_FO_AM_MSK	7		/* Bit  2.. 0:	Fiber Output Amplitude */
+
+/*****  PHY_MARV_CABLE_DIAG	16 bit r/o	Cable Diagnostic Reg *****/
+#define PHY_M_CABD_ENA_TEST	(1<<15)	/* Bit 15:	Enable Test */
+#define PHY_M_CABD_STAT_MSK	(3<<13)	/* Bit 14..13:	Status */
+									/* Bit 12.. 8:	reserved */
+#define PHY_M_CABD_DIST_MSK	0xff	/* Bit  7.. 0:	Distance */
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+#define CABD_STAT_NORMAL	0
+#define CABD_STAT_SHORT		1
+#define CABD_STAT_OPEN		2
+#define CABD_STAT_FAIL		3
+
+
+/*
+ * GMAC registers
+ *
+ * The GMAC registers are 16 or 32 bits wide.
+ * The GMACs host processor interface is 16 bits wide,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the GMAC registers
+ * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(),
+ * GM_INHASH(), and GM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+
+/* Port Registers */
+#define GM_GP_STAT		0x0000		/* 16 bit r/o	General Purpose Status */
+#define GM_GP_CTRL		0x0004		/* 16 bit r/w	General Purpose Control */
+#define GM_TX_CTRL		0x0008		/* 16 bit r/w	Transmit Control Reg. */
+#define GM_RX_CTRL		0x000c		/* 16 bit r/w	Receive Control Reg. */
+#define GM_TX_FLOW_CTRL	0x0010		/* 16 bit r/w	Transmit Flow Control */
+#define GM_TX_PARAM		0x0014		/* 16 bit r/w	Transmit Parameter Reg. */
+#define GM_SERIAL_MODE	0x0018		/* 16 bit r/w	Serial Mode Register */
+
+/* Source Address Registers */
+#define GM_SRC_ADDR_1L	0x001c		/* 16 bit r/w	Source Address 1 (low) */
+#define GM_SRC_ADDR_1M	0x0020		/* 16 bit r/w	Source Address 1 (middle) */
+#define GM_SRC_ADDR_1H	0x0024		/* 16 bit r/w	Source Address 1 (high) */
+#define GM_SRC_ADDR_2L	0x0028		/* 16 bit r/w	Source Address 2 (low) */
+#define GM_SRC_ADDR_2M	0x002c		/* 16 bit r/w	Source Address 2 (middle) */
+#define GM_SRC_ADDR_2H	0x0030		/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+#define GM_MC_ADDR_H1	0x0034		/* 16 bit r/w	Multicast Address Hash 1 */
+#define GM_MC_ADDR_H2	0x0038		/* 16 bit r/w	Multicast Address Hash 2 */
+#define GM_MC_ADDR_H3	0x003c		/* 16 bit r/w	Multicast Address Hash 3 */
+#define GM_MC_ADDR_H4	0x0040		/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+#define GM_TX_IRQ_SRC	0x0044		/* 16 bit r/o	Tx Overflow IRQ Source */
+#define GM_RX_IRQ_SRC	0x0048		/* 16 bit r/o	Rx Overflow IRQ Source */
+#define GM_TR_IRQ_SRC	0x004c		/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+#define GM_TX_IRQ_MSK	0x0050		/* 16 bit r/w	Tx Overflow IRQ Mask */
+#define GM_RX_IRQ_MSK	0x0054		/* 16 bit r/w	Rx Overflow IRQ Mask */
+#define GM_TR_IRQ_MSK	0x0058		/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+#define GM_SMI_CTRL		0x0080		/* 16 bit r/w	SMI Control Register */
+#define GM_SMI_DATA		0x0084		/* 16 bit r/w	SMI Data Register */
+#define GM_PHY_ADDR		0x0088		/* 16 bit r/w	GPHY Address Register */
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE	0x0100		/* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE	44			/* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+#define GM_RXF_UC_OK \
+			(GM_MIB_CNT_BASE + 0)	/* Unicast Frames Received OK */
+#define GM_RXF_BC_OK \
+			(GM_MIB_CNT_BASE + 8)	/* Broadcast Frames Received OK */
+#define GM_RXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 16)	/* Pause MAC Ctrl Frames Received */
+#define GM_RXF_MC_OK \
+			(GM_MIB_CNT_BASE + 24)	/* Multicast Frames Received OK */
+#define GM_RXF_FCS_ERR \
+			(GM_MIB_CNT_BASE + 32)	/* Rx Frame Check Seq. Error */
+	/* GM_MIB_CNT_BASE + 40:	reserved */
+#define GM_RXO_OK_LO \
+			(GM_MIB_CNT_BASE + 48)	/* Octets Received OK Low */
+#define GM_RXO_OK_HI \
+			(GM_MIB_CNT_BASE + 56)	/* Octets Received OK High */
+#define GM_RXO_ERR_LO \
+			(GM_MIB_CNT_BASE + 64)	/* Octets Received Invalid Low */
+#define GM_RXO_ERR_HI \
+			(GM_MIB_CNT_BASE + 72)	/* Octets Received Invalid High */
+#define GM_RXF_SHT \
+			(GM_MIB_CNT_BASE + 80)	/* Frames <64 Byte Received OK */
+#define GM_RXE_FRAG \
+			(GM_MIB_CNT_BASE + 88)	/* Frames <64 Byte Receeived with FCS Err */
+#define GM_RXF_64B \
+			(GM_MIB_CNT_BASE + 96)	/* 64 Byte Rx Frame */
+#define GM_RXF_127B \
+			(GM_MIB_CNT_BASE + 104)	/* 65-127 Byte Rx Frame */
+#define GM_RXF_255B \
+			(GM_MIB_CNT_BASE + 112)	/* 128-255 Byte Rx Frame */
+#define GM_RXF_511B \
+			(GM_MIB_CNT_BASE + 120)	/* 256-511 Byte Rx Frame */
+#define GM_RXF_1023B \
+			(GM_MIB_CNT_BASE + 128)	/* 512-1023 Byte Rx Frame */
+#define GM_RXF_1518B \
+			(GM_MIB_CNT_BASE + 136)	/* 1024-1518 Byte Rx Frame */
+#define GM_RXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 144)	/* 1519-MaxSize Byte Rx Frame */
+#define GM_RXF_LNG_ERR \
+			(GM_MIB_CNT_BASE + 152)	/* Rx Frame too Long Error */
+#define GM_RXF_JAB_PKT \
+			(GM_MIB_CNT_BASE + 160)	/* Rx Jabber Packet Frame */
+	/* GM_MIB_CNT_BASE + 168:	reserved */
+#define GM_RXE_FIFO_OV \
+			(GM_MIB_CNT_BASE + 176)	/* Rx FIFO overflow Event */
+	/* GM_MIB_CNT_BASE + 184:	reserved */
+#define GM_TXF_UC_OK \
+			(GM_MIB_CNT_BASE + 192)	/* Unicast Frames Xmitted OK */
+#define GM_TXF_BC_OK \
+			(GM_MIB_CNT_BASE + 200)	/* Broadcast Frames Xmitted OK */
+#define GM_TXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 208)	/* Pause MAC Ctrl Frames Xmitted */
+#define GM_TXF_MC_OK \
+			(GM_MIB_CNT_BASE + 216)	/* Multicast Frames Xmitted OK */
+#define GM_TXO_OK_LO \
+			(GM_MIB_CNT_BASE + 224)	/* Octets Transmitted OK Low */
+#define GM_TXO_OK_HI \
+			(GM_MIB_CNT_BASE + 232)	/* Octets Transmitted OK High */
+#define GM_TXF_64B \
+			(GM_MIB_CNT_BASE + 240)	/* 64 Byte Tx Frame */
+#define GM_TXF_127B \
+			(GM_MIB_CNT_BASE + 248)	/* 65-127 Byte Tx Frame */
+#define GM_TXF_255B \
+			(GM_MIB_CNT_BASE + 256)	/* 128-255 Byte Tx Frame */
+#define GM_TXF_511B \
+			(GM_MIB_CNT_BASE + 264)	/* 256-511 Byte Tx Frame */
+#define GM_TXF_1023B \
+			(GM_MIB_CNT_BASE + 272)	/* 512-1023 Byte Tx Frame */
+#define GM_TXF_1518B \
+			(GM_MIB_CNT_BASE + 280)	/* 1024-1518 Byte Tx Frame */
+#define GM_TXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 288)	/* 1519-MaxSize Byte Tx Frame */
+	/* GM_MIB_CNT_BASE + 296:	reserved */
+#define GM_TXF_COL \
+			(GM_MIB_CNT_BASE + 304)	/* Tx Collision */
+#define GM_TXF_LAT_COL \
+			(GM_MIB_CNT_BASE + 312)	/* Tx Late Collision */
+#define GM_TXF_ABO_COL \
+			(GM_MIB_CNT_BASE + 320)	/* Tx aborted due to Exces. Col. */
+#define GM_TXF_MUL_COL \
+			(GM_MIB_CNT_BASE + 328)	/* Tx Multiple Collision */
+#define GM_TXF_SNG_COL \
+			(GM_MIB_CNT_BASE + 336)	/* Tx Single Collision */
+#define GM_TXE_FIFO_UR \
+			(GM_MIB_CNT_BASE + 344)	/* Tx FIFO Underrun Event */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * GMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *	(sc)	self clearing
+ *	(r/o)	read only
+ */
+
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+
+#define GM_GPSR_SPEED		(1<<15) /* Bit 15:	Port Speed (1 = 100 Mbps) */
+#define GM_GPSR_DUPLEX		(1<<14) /* Bit 14:	Duplex Mode (1 = Full) */
+#define GM_GPSR_FC_TX_DIS	(1<<13) /* Bit 13:	Tx Flow Control Mode Disabled */
+#define GM_GPSR_LINK_UP		(1<<12)	/* Bit 12:	Link Up Status */
+#define GM_GPSR_PAUSE		(1<<11)	/* Bit 11:	Pause State */
+#define GM_GPSR_TX_ACTIVE	(1<<10)	/* Bit 10:	Tx in Progress */
+#define GM_GPSR_EXC_COL		(1<<9)	/* Bit  9:	Excessive Collisions Occured */
+#define GM_GPSR_LAT_COL		(1<<8)	/* Bit  8:	Late Collisions Occured */
+								/* Bit  7..6:	reserved */
+#define GM_GPSR_PHY_ST_CH	(1<<5)	/* Bit  5:	PHY Status Change */
+#define GM_GPSR_GIG_SPEED	(1<<4)	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+#define GM_GPSR_PART_MODE	(1<<3)	/* Bit  3:	Partition mode */
+#define GM_GPSR_FC_RX_DIS	(1<<2)	/* Bit  2:	Rx Flow Control Mode Disabled */
+#define GM_GPSR_PROM_EN		(1<<1)	/* Bit  1:	Promiscuous Mode Enabled */
+								/* Bit  0:	reserved */
+
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+								/* Bit 15:	reserved */
+#define GM_GPCR_PROM_ENA	(1<<14)	/* Bit 14:	Enable Promiscuous Mode */
+#define GM_GPCR_FC_TX_DIS	(1<<13) /* Bit 13:	Disable Tx Flow Control Mode */
+#define GM_GPCR_TX_ENA		(1<<12) /* Bit 12:	Enable Transmit */
+#define GM_GPCR_RX_ENA		(1<<11) /* Bit 11:	Enable Receive */
+#define GM_GPCR_BURST_ENA	(1<<10)	/* Bit 10:	Enable Burst Mode */
+#define GM_GPCR_LOOP_ENA	(1<<9)	/* Bit  9:	Enable MAC Loopback Mode */
+#define GM_GPCR_PART_ENA	(1<<8)	/* Bit  8:	Enable Partition Mode */
+#define GM_GPCR_GIGS_ENA	(1<<7)	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+#define GM_GPCR_FL_PASS		(1<<6)	/* Bit  6:	Force Link Pass */
+#define GM_GPCR_DUP_FULL	(1<<5)	/* Bit  5:	Full Duplex Mode */
+#define GM_GPCR_FC_RX_DIS	(1<<4)	/* Bit  4:	Disable Rx Flow Control Mode */
+#define GM_GPCR_SPEED_100	(1<<3)  /* Bit  3:	Port Speed 100 Mbps */
+#define GM_GPCR_AU_DUP_DIS	(1<<2)	/* Bit  2:	Disable Auto-Update for Duplex */
+#define GM_GPCR_AU_FCT_DIS	(1<<1)	/* Bit  1:	Disable Auto-Update for Flow-c. */
+#define GM_GPCR_AU_SPD_DIS	(1<<0)	/* Bit  0:	Disable Auto-Update for Speed */
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\
+							 GM_GPCR_AU_SPD_DIS)
+
+/*	GM_TX_CTRL				16 bit r/w	Transmit Control Register */
+
+#define GM_TXCR_FORCE_JAM	(1<<15)	/* Bit 15:	Force Jam / Flow-Control */
+#define GM_TXCR_CRC_DIS		(1<<14)	/* Bit 14:	Disable insertion of CRC */
+#define GM_TXCR_PAD_DIS		(1<<13)	/* Bit 13:	Disable padding of packets */
+#define GM_TXCR_COL_THR		(4<<10)	/* Bit 12..10:	Collision Threshold */
+
+/*	GM_RX_CTRL				16 bit r/w	Receive Control Register */
+#define GM_RXCR_UCF_ENA		(1<<15)	/* Bit 15:	Enable Unicast filtering */
+#define GM_RXCR_MCF_ENA		(1<<14)	/* Bit 14:	Enable Multicast filtering */
+#define GM_RXCR_CRC_DIS		(1<<13)	/* Bit 13:	Remove 4-byte CRC */
+#define GM_RXCR_PASS_FC		(1<<12)	/* Bit 12:	Pass FC packets to FIFO */
+
+/*	GM_TX_PARAM				16 bit r/w	Transmit Parameter Register */
+#define GM_TXPA_JAMLEN_MSK	(0x03<<14)	/* Bit 15..14:	Jam Length */
+#define GM_TXPA_JAMIPG_MSK	(0x1f<<9)	/* Bit 13..9:	Jam IPG */
+#define GM_TXPA_JAMDAT_MSK	(0x1f<<4)	/* Bit  8..4:	IPG Jam to Data */
+								/* Bit  3..0:	reserved */
+#define JAM_LEN_VAL(x)		SHIFT14(x)
+#define JAM_IPG_VAL(x)		SHIFT9(x)
+#define IPG_JAM_DATA(x)		SHIFT4(x)
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+#define GM_SMOD_DATABL_MSK	(0x1f<<11)	/* Bit 15..11:	Data Blinder */
+#define GM_SMOD_LIMIT_4		(1<<10)	/* Bit 10:	4 consecutive transmit trials */
+#define GM_SMOD_VLAN_ENA	(1<<9)	/* Bit  9:	Enable VLAN  (Max. Frame Length) */
+#define GM_SMOD_JUMBO_ENA	(1<<8)	/* Bit  8:	Enable Jumbo (Max. Frame Length) */
+								/* Bit  7..5:	reserved */
+#define GM_SMOD_IPG_MSK		0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+
+#define DATA_BLIND_VAL(x)	SHIFT11(x)
+#define DATA_BLIND_FAST_ETH	0x1c
+#define DATA_BLIND_GIGABIT	4
+
+#define IPG_VAL_FAST_ETH	0x1e
+#define IPG_VAL_GIGABIT		6
+
+/*	GM_SMI_CTRL				16 bit r/w	SMI Control Register */
+
+#define GM_SMI_CT_PHY_AD(x)	SHIFT11(x)
+#define GM_SMI_CT_REG_AD(x)	SHIFT6(x)
+#define GM_SMI_CT_OP_RD		(1<<5)	/* Bit  5:	OpCode Read (0=Write)*/
+#define GM_SMI_CT_RD_VAL	(1<<4)	/* Bit  4:	Read Valid (Read completed) */
+#define GM_SMI_CT_BUSY		(1<<3)	/* Bit  3:	Busy (Operation in progress) */
+								/* Bit   2..0:	reserved */
+
+/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+								/* Bit  15..6:	reserved */
+#define GM_PAR_MIB_CLR		(1<<5)	/* Bit  5:	Set MIB Clear Counter Mode */
+#define GM_PAR_MIB_TST		(1<<4)	/* Bit  4:	MIB Load Counter (Test Mode) */
+								/* Bit   3..0:	reserved */
+
+/* Receive Frame Status Encoding */
+#define GMR_FS_LEN	(0xffffUL<<16)	/* Bit 31..16:	Rx Frame Length */
+								/* Bit  15..14:	reserved */
+#define GMR_FS_VLAN		(1L<<13)	/* Bit 13:	VLAN Packet */
+#define GMR_FS_JABBER	(1L<<12)	/* Bit 12:	Jabber Packet */
+#define GMR_FS_UN_SIZE	(1L<<11)	/* Bit 11:	Undersize Packet */
+#define GMR_FS_MC		(1L<<10)	/* Bit 10:	Multicast Packet */
+#define GMR_FS_BC		(1L<<9)		/* Bit  9:	Broadcast Packet */
+#define GMR_FS_RX_OK	(1L<<8)		/* Bit  8:	Receive OK (Good Packet) */
+#define GMR_FS_GOOD_FC	(1L<<7)		/* Bit  7:	Good Flow-Control Packet */
+#define GMR_FS_BAD_FC	(1L<<6)		/* Bit  6:	Bad  Flow-Control Packet */
+#define GMR_FS_MII_ERR	(1L<<5)		/* Bit  5:	MII Error */
+#define GMR_FS_LONG_ERR	(1L<<4)		/* Bit  4:	Too Long Packet */
+#define GMR_FS_FRAGMENT	(1L<<3)		/* Bit  3:	Fragment */
+								/* Bit  2:	reserved */
+#define GMR_FS_CRC_ERR	(1L<<1)		/* Bit  1:	CRC Error */
+#define GMR_FS_RX_FF_OV	(1L<<0)		/* Bit  0:	Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+#define GMR_FS_ANY_ERR	(GMR_FS_CRC_ERR | \
+			GMR_FS_LONG_ERR | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_JABBER)
+
+/* Rx GMAC FIFO Flush Mask (default) */
+#define RX_FF_FL_DEF_MSK	(GMR_FS_CRC_ERR | \
+			GMR_FS_RX_FF_OV | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_UN_SIZE | \
+			GMR_FS_JABBER)
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_XMAC_H */
diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c
new file mode 100644
index 0000000..ed79c04
--- /dev/null
+++ b/drivers/net/sk98lin/skaddr.c
@@ -0,0 +1,1879 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.48 $
+ * Date:	$Date: 2003/02/12 17:09:37 $
+ * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skaddr.c,v $
+ *	Revision 1.48  2003/02/12 17:09:37  tschilli
+ *	Fix in SkAddrOverride() to set both (physical and logical) MAC addresses
+ *	in case that both addresses are identical.
+ *
+ *	Revision 1.47  2002/09/17 06:31:10  tschilli
+ *	Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate()
+ *	and SkAddrGmacPromiscuousChange() fixed.
+ *	Editorial changes.
+ *
+ *	Revision 1.46  2002/08/22 07:55:41  tschilli
+ *	New function SkGmacMcHash() for GMAC multicast hashing algorithm added.
+ *	Editorial changes.
+ *
+ *	Revision 1.45  2002/08/15 12:29:35  tschilli
+ *	SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed.
+ *
+ *	Revision 1.44  2002/08/14 12:18:03  rschmidt
+ *	Replaced direct handling of MAC Hashing (XMAC and GMAC)
+ *	with routine SkMacHashing().
+ *	Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode().
+ *
+ *	Revision 1.43  2002/08/13 09:37:43  rschmidt
+ *	Corrected some SK_DBG_MSG outputs.
+ *	Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode().
+ *	Editorial changes.
+ *
+ *	Revision 1.42  2002/08/12 11:24:36  rschmidt
+ *	Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit().
+ *	Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC)
+ *	with routine SkMacPromiscMode().
+ *	Editorial changes.
+ *
+ *	Revision 1.41  2002/06/10 13:52:18  tschilli
+ *	Changes for handling YUKON.
+ *	All changes are internally and not visible to the programmer
+ *	using this module.
+ *
+ *	Revision 1.40  2001/02/14 14:04:59  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.39  2001/01/30 10:30:04  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.38  2001/01/25 16:26:52  rassmann
+ *	Ensured that logical address overrides are done on net's active port.
+ *
+ *	Revision 1.37  2001/01/22 13:41:34  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.36  2000/08/07 11:10:39  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.35  2000/05/04 09:38:41  rassmann
+ *	Editorial changes.
+ *	Corrected multicast address hashing.
+ *
+ *	Revision 1.34  1999/11/22 13:23:44  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.33  1999/05/28 10:56:06  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.32  1999/03/31 10:59:20  rassmann
+ *	Returning Success instead of DupAddr if address shall be overridden
+ *	with same value.
+ *
+ *	Revision 1.31  1999/01/14 16:18:17  rassmann
+ *	Corrected multicast initialization.
+ *
+ *	Revision 1.30  1999/01/04 10:30:35  rassmann
+ *	SkAddrOverride only possible after SK_INIT_IO phase.
+ *
+ *	Revision 1.29  1998/12/29 13:13:10  rassmann
+ *	An address override is now preserved in the SK_INIT_IO phase.
+ *	All functions return an int now.
+ *	Extended parameter checking.
+ *
+ *	Revision 1.28  1998/12/01 11:45:53  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.27  1998/12/01 09:22:49  rassmann
+ *	SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT
+ *	too often.
+ *
+ *	Revision 1.26  1998/11/24 12:39:44  rassmann
+ *	Reserved multicast entry for BPDU address.
+ *	13 multicast entries left for protocol.
+ *
+ *	Revision 1.25  1998/11/17 16:54:23  rassmann
+ *	Using exact match for up to 14 multicast addresses.
+ *	Still receiving all multicasts if more addresses are added.
+ *
+ *	Revision 1.24  1998/11/13 17:24:31  rassmann
+ *	Changed return value of SkAddrOverride to int.
+ *
+ *	Revision 1.23  1998/11/13 16:56:18  rassmann
+ *	Added macro SK_ADDR_COMPARE.
+ *	Changed return type of SkAddrOverride to SK_BOOL.
+ *
+ *	Revision 1.22  1998/11/04 17:06:17  rassmann
+ *	Corrected McUpdate and PromiscuousChange functions.
+ *
+ *	Revision 1.21  1998/10/29 14:34:04  rassmann
+ *	Clearing SK_ADDR struct at startup.
+ *
+ *	Revision 1.20  1998/10/28 18:16:34  rassmann
+ *	Avoiding I/Os before SK_INIT_RUN level.
+ *	Aligning InexactFilter.
+ *
+ *	Revision 1.19  1998/10/28 11:29:28  rassmann
+ *	Programming physical address in SkAddrMcUpdate.
+ *	Corrected programming of exact match entries.
+ *
+ *	Revision 1.18  1998/10/28 10:34:48  rassmann
+ *	Corrected reading of physical addresses.
+ *
+ *	Revision 1.17  1998/10/28 10:26:13  rassmann
+ *	Getting ports' current MAC addresses from EPROM now.
+ *	Added debug output.
+ *
+ *	Revision 1.16  1998/10/27 16:20:12  rassmann
+ *	Reading MAC address byte by byte.
+ *
+ *	Revision 1.15  1998/10/22 11:39:09  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *
+ *	Revision 1.14  1998/10/19 17:12:35  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.13  1998/10/19 17:02:19  rassmann
+ *	Now reading permanent MAC addresses from CRF.
+ *
+ *	Revision 1.12  1998/10/15 15:15:48  rassmann
+ *	Changed Flags Parameters from SK_U8 to int.
+ *	Checked with lint.
+ *
+ *	Revision 1.11  1998/09/24 19:15:12  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.10  1998/09/18 20:18:54  rassmann
+ *	Added HW access.
+ *	Implemented swapping.
+ *
+ *	Revision 1.9  1998/09/16 11:32:00  rassmann
+ *	Including skdrv1st.h again. :(
+ *
+ *	Revision 1.8  1998/09/16 11:09:34  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.7  1998/09/14 17:06:34  rassmann
+ *	Minor changes.
+ *
+ *	Revision 1.6  1998/09/07 08:45:41  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.5  1998/09/04 19:40:19  rassmann
+ *	Interface enhancements.
+ *
+ *	Revision 1.4  1998/09/04 12:14:12  rassmann
+ *	Interface cleanup.
+ *
+ *	Revision 1.3  1998/09/02 16:56:40  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.2  1998/08/27 14:26:09  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.1  1998/08/21 08:30:22  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses, address override,
+ * and promiscuous mode on GEnesis and Yukon adapters.
+ *
+ * Address Layout:
+ *	port address:		physical MAC address
+ *	1st exact match:	logical MAC address (GEnesis only)
+ *	2nd exact match:	RLMT multicast (GEnesis only)
+ *	exact match 3-13:	OS-specific multicasts (GEnesis only)
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skaddr.c,v 1.48 2003/02/12 17:09:37 tschilli Exp $ (C) SysKonnect.";
+#endif	/* !defined(lint) */
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+
+#define XMAC_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
+#define GMAC_POLY	0x04C11DB7L	/* CRC16-Poly - GMAC: Little Endian */
+#define HASH_BITS	6				/* #bits in hash */
+#define	SK_MC_BIT	0x01
+
+/* Error numbers and messages. */
+
+#define SKERR_ADDR_E001		(SK_ERRBASE_ADDR + 0)
+#define SKERR_ADDR_E001MSG	"Bad Flags."
+#define SKERR_ADDR_E002		(SKERR_ADDR_E001 + 1)
+#define SKERR_ADDR_E002MSG	"New Error."
+
+/* typedefs *******************************************************************/
+
+/* None. */
+
+/* global variables ***********************************************************/
+
+/* 64-bit hash values with all bits set. */
+
+SK_U16	OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+
+/* local variables ************************************************************/
+
+#ifdef DEBUG
+static int	Next0[SK_MAX_MACS] = {0, 0};
+#endif	/* DEBUG */
+
+/* functions ******************************************************************/
+
+/******************************************************************************
+ *
+ *	SkAddrInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine clears the multicast tables and resets promiscuous mode.
+ *	Some entries are reserved for the "logical MAC address", the
+ *	SK-RLMT multicast address, and the BPDU multicast address.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	All permanent MAC addresses are read from EPROM.
+ *	If the current MAC addresses are not already set in software,
+ *	they are set to the values of the permanent addresses.
+ *	The current addresses are written to the corresponding MAC.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Nothing.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ */
+int	SkAddrInit(
+SK_AC	*pAC,	/* the adapter context */
+SK_IOC	IoC,	/* I/O context */
+int		Level)	/* initialization level */
+{
+	int			j;
+	SK_U32		i;
+	SK_U8		*InAddr;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		SK_MEMSET((char *) &pAC->Addr, 0, sizeof(SK_ADDR));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAPort = &pAC->Addr.Port[i];
+			pAPort->PromMode = SK_PROM_MODE_NONE;
+
+			pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+			pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+		}
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 4;
+			}
+		}
+#endif	/* DEBUG */
+		/* pAC->Addr.InitDone = SK_INIT_DATA; */
+		break;
+
+	case SK_INIT_IO:
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
+		}
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 8;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* Read permanent logical MAC address from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+			InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
+			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
+		}
+
+		if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[0].CurrentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
+		}
+
+		/* Set the current logical MAC address. */
+		pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
+			pAC->Addr.Net[0].CurrentMacAddress;
+#if SK_MAX_NETS > 1
+		/* Set logical MAC address for net 2 to (log | 3). */
+		if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
+			pAC->Addr.Net[1].PermanentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[1].CurrentMacAddress =
+				pAC->Addr.Net[1].PermanentMacAddress;
+			pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
+		}
+#endif	/* SK_MAX_NETS > 1 */
+
+#ifdef DEBUG
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].PermanentMacAddress.a[0],
+					pAC->Addr.Net[i].PermanentMacAddress.a[1],
+					pAC->Addr.Net[i].PermanentMacAddress.a[2],
+					pAC->Addr.Net[i].PermanentMacAddress.a[3],
+					pAC->Addr.Net[i].PermanentMacAddress.a[4],
+					pAC->Addr.Net[i].PermanentMacAddress.a[5]))
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].CurrentMacAddress.a[0],
+					pAC->Addr.Net[i].CurrentMacAddress.a[1],
+					pAC->Addr.Net[i].CurrentMacAddress.a[2],
+					pAC->Addr.Net[i].CurrentMacAddress.a[3],
+					pAC->Addr.Net[i].CurrentMacAddress.a[4],
+					pAC->Addr.Net[i].CurrentMacAddress.a[5]))
+		}
+#endif	/* DEBUG */
+
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			pAPort = &pAC->Addr.Port[i];
+
+			/* Read permanent port addresses from Control Register File. */
+			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+				InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
+				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
+			}
+
+			if (!pAPort->CurrentMacAddressSet) {
+				/*
+				 * Set the current and previous physical MAC address
+				 * of this port to its permanent MAC address.
+				 */
+				pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
+				pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
+				pAPort->CurrentMacAddressSet = SK_TRUE;
+			}
+
+			/* Set port's current physical MAC address. */
+			OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+
+			if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+				XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+			}
+			else {
+				GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+			}
+#ifdef DEBUG
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->PermanentMacAddress.a[0],
+					pAPort->PermanentMacAddress.a[1],
+					pAPort->PermanentMacAddress.a[2],
+					pAPort->PermanentMacAddress.a[3],
+					pAPort->PermanentMacAddress.a[4],
+					pAPort->PermanentMacAddress.a[5]))
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->CurrentMacAddress.a[0],
+					pAPort->CurrentMacAddress.a[1],
+					pAPort->CurrentMacAddress.a[2],
+					pAPort->CurrentMacAddress.a[3],
+					pAPort->CurrentMacAddress.a[4],
+					pAPort->CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+		}
+		/* pAC->Addr.InitDone = SK_INIT_IO; */
+		break;
+
+	case SK_INIT_RUN:
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 16;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* pAC->Addr.InitDone = SK_INIT_RUN; */
+		break;
+
+	default:	/* error */
+		break;
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrInit */
+
+
+/******************************************************************************
+ *
+ *	SkAddrMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table.
+ *
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ *	It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
+ *	to the adapter in use. The real work is done there.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int ReturnCode;
+
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcClear */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table
+ *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+
+		/* Clear RLMT multicast addresses. */
+		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+	}
+	else {	/* not permanent => DRV */
+
+		/* Clear InexactFilter */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+		}
+
+		/* Clear DRV multicast addresses. */
+
+		pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+	}
+
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrXmacMcClear */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast hashing table (InexactFilter)
+ *	(either the RLMT or the driver bits) of the given port.
+ *
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+
+	/* Clear InexactFilter */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+	}
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+
+		/* Copy DRV bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+
+			/* Clear InexactRlmtFilter. */
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
+
+		}
+	}
+	else {	/* not permanent => DRV */
+
+		/* Copy RLMT bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+
+			/* Clear InexactDrvFilter. */
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
+		}
+	}
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrGmacMcClear */
+
+#ifndef SK_ADDR_CHEAT
+
+/******************************************************************************
+ *
+ *	SkXmacMcHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *	A CRC32 algorithm is used.
+ *
+ * Notes:
+ *	The code was adapted from the XaQti data sheet.
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+SK_U32 SkXmacMcHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	SK_U32 Idx;
+	SK_U32 Bit;
+	SK_U32 Data;
+	SK_U32 Crc;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+		Data = *pMc++;
+		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
+		}
+	}
+
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkXmacMcHash */
+
+
+/******************************************************************************
+ *
+ *	SkGmacMcHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *	A CRC16 algorithm is used.
+ *
+ * Notes:
+ *
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+SK_U32 SkGmacMcHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	SK_U32 Data;
+	SK_U32 TmpData;
+	SK_U32 Crc;
+	int Byte;
+	int Bit;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Byte = 0; Byte < 6; Byte++) {
+		/* Get next byte. */
+		Data = (SK_U32) pMc[Byte];
+
+		/* Change bit order in byte. */
+		TmpData = Data;
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (TmpData & 1L) {
+				Data |=  1L << (7 - Bit);
+			}
+			else {
+				Data &= ~(1L << (7 - Bit));
+			}
+			TmpData >>= 1;
+		}
+
+		Crc ^= (Data << 24);
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (Crc & 0x80000000) {
+				Crc = (Crc << 1) ^ GMAC_POLY;
+			}
+			else {
+				Crc <<= 1;
+			}
+		}
+	}
+
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkGmacMcHash */
+
+#endif	/* not SK_ADDR_CHEAT */
+
+/******************************************************************************
+ *
+ *	SkAddrMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ *	It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
+ *	adapter in use. The real work is done there.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_ILLEGAL_PORT
+ *	SK_MC_RLMT_OVERFLOW
+ */
+int	SkAddrMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int			Flags)		/* permanent/non-permanent */
+{
+	int ReturnCode;
+
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ *	The multicast bit is only checked if there are no free exact match
+ *	entries.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_RLMT_OVERFLOW
+ */
+int	SkAddrXmacMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
+{
+	int	i;
+	SK_U8	Inexact;
+#ifndef SK_ADDR_CHEAT
+	SK_U32 HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+#ifdef xDEBUG
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
+			SK_ADDR_FIRST_MATCH_RLMT) {
+			Next0[PortNumber] |= 1;
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+#endif	/* DEBUG */
+
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
+			SK_ADDR_LAST_MATCH_RLMT) {
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+
+		/* Set a RLMT multicast address. */
+
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
+
+		return (SK_MC_FILTERING_EXACT);
+	}
+
+#ifdef xDEBUG
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
+		SK_ADDR_FIRST_MATCH_DRV) {
+			Next0[PortNumber] |= 2;
+		return (SK_MC_RLMT_OVERFLOW);
+	}
+#endif	/* DEBUG */
+
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+		/* Set exact match entry. */
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
+
+		/* Clear InexactFilter */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+		}
+	}
+	else {
+		if (!(pMc->a[0] & SK_MC_BIT)) {
+			/* Hashing only possible with multicast addresses. */
+			return (SK_MC_ILLEGAL_ADDRESS);
+		}
+#ifndef SK_ADDR_CHEAT
+		/* Compute hash value of address. */
+		HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
+
+		/* Add bit to InexactFilter. */
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+#else	/* SK_ADDR_CHEAT */
+		/* Set all bits in InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+		}
+#endif	/* SK_ADDR_CHEAT */
+	}
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+	}
+
+	if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+
+}	/* SkAddrXmacMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ */
+int	SkAddrGmacMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
+{
+	int	i;
+#ifndef SK_ADDR_CHEAT
+	SK_U32 HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+
+	if (!(pMc->a[0] & SK_MC_BIT)) {
+		/* Hashing only possible with multicast addresses. */
+		return (SK_MC_ILLEGAL_ADDRESS);
+	}
+
+#ifndef SK_ADDR_CHEAT
+
+	/* Compute hash value of address. */
+	HashBit = SkGmacMcHash(&pMc->a[0]);
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+
+		/* Add bit to InexactRlmtFilter. */
+		pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+		}
+#ifdef DEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
+#endif	/* DEBUG */
+	}
+	else {	/* not permanent => DRV */
+
+		/* Add bit to InexactDrvFilter. */
+		pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+		}
+#ifdef DEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
+#endif	/* DEBUG */
+	}
+
+#else	/* SK_ADDR_CHEAT */
+
+	/* Set all bits in InexactFilter. */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+	}
+#endif	/* SK_ADDR_CHEAT */
+
+	return (SK_MC_FILTERING_INEXACT);
+
+}	/* SkAddrGmacMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ *	It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
+ *	to the adapter in use. The real work is done there.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	int ReturnCode;
+
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
+
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif	/* DEBUG */
+
+	/* Start with 0 to also program the logical MAC address. */
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+		/* Set exact match address i on XMAC */
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+	}
+
+	/* Clear other permanent exact match addresses on XMAC */
+	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
+
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
+			SK_ADDR_LAST_MATCH_RLMT);
+	}
+
+	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+	}
+
+	/* Clear other non-permanent exact match addresses on XMAC */
+	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
+			SK_ADDR_LAST_MATCH_DRV);
+	}
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+
+		/* Set all bits in 64-bit hash register. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else if (Inexact != 0) {
+
+		/* Set 64-bit hash register to InexactFilter. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else {
+		/* Disable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
+	}
+
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+
+	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+
+#ifdef xDEBUG
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+		SK_U8		InAddr8[6];
+		SK_U16		*InAddr;
+
+		/* Get exact match address i from port PortNumber. */
+		InAddr = (SK_U16 *) &InAddr8[0];
+
+		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
+			 "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
+				i,
+				PortNumber,
+				InAddr8[0],
+				InAddr8[1],
+				InAddr8[2],
+				InAddr8[3],
+				InAddr8[4],
+				InAddr8[5],
+				pAPort->Exact[i].a[0],
+				pAPort->Exact[i].a[1],
+				pAPort->Exact[i].a[2],
+				pAPort->Exact[i].a[3],
+				pAPort->Exact[i].a[4],
+				pAPort->Exact[i].a[5]))
+	}
+#endif	/* DEBUG */
+
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+
+}	/* SkAddrXmacMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
+
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif	/* DEBUG */
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+
+	/* Set 64-bit hash register to InexactFilter. */
+	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+		&pAPort->InexactFilter.Bytes[0]);
+
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else {
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+
+	/* Set port's current logical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->Exact[0].a[0],
+			pAPort->Exact[0].a[1],
+			pAPort->Exact[0].a[2],
+			pAPort->Exact[0].a[3],
+			pAPort->Exact[0].a[4],
+			pAPort->Exact[0].a[5]))
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->CurrentMacAddress.a[0],
+			pAPort->CurrentMacAddress.a[1],
+			pAPort->CurrentMacAddress.a[2],
+			pAPort->CurrentMacAddress.a[3],
+			pAPort->CurrentMacAddress.a[4],
+			pAPort->CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+
+}	/* SkAddrGmacMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrOverride - override a port's MAC address
+ *
+ * Description:
+ *	This routine overrides the MAC address of one port.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS if successful.
+ *	SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
+ *	SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
+ *	SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
+ */
+int	SkAddrOverride(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pNewAddr,	/* new MAC address */
+int			Flags)		/* logical/physical MAC address */
+{
+	SK_EVPARA	Para;
+	SK_U32		NetNumber;
+	SK_U32		i;
+	SK_U16		*OutAddr;
+
+	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
+
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
+		return (SK_ADDR_MULTICAST_ADDRESS);
+	}
+
+	if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
+		return (SK_ADDR_TOO_EARLY);
+	}
+
+	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+		}
+
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		pAC->Addr.Port[PortNumber].Exact[0] =
+			pAC->Addr.Net[NetNumber].CurrentMacAddress;
+
+		/* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+	else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
+		/* Deactivate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+		}
+
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
+			pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
+		}
+
+		/* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+			return (SK_ADDR_DUPLICATE_ADDRESS);
+		}
+
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				if (i == PortNumber) {
+					return (SK_ADDR_SUCCESS);
+				}
+				else {
+					return (SK_ADDR_DUPLICATE_ADDRESS);
+				}
+			}
+		}
+
+		pAC->Addr.Port[PortNumber].PreviousMacAddress =
+			pAC->Addr.Port[PortNumber].CurrentMacAddress;
+		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+		/* Change port's physical MAC address. */
+		OutAddr = (SK_U16 *) pNewAddr;
+
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		}
+		else {
+			GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+		}
+
+		/* Report address change to RLMT. */
+		Para.Para32[0] = PortNumber;
+		Para.Para32[0] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+	}
+	else {	/* Logical MAC address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+			return (SK_ADDR_SUCCESS);
+		}
+
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				return (SK_ADDR_DUPLICATE_ADDRESS);
+			}
+		}
+
+		/*
+		 * In case that the physical and the logical MAC addresses are equal
+		 * we must also change the physical MAC address here.
+		 * In this case we have an adapter which initially was programmed with
+		 * two identical MAC addresses.
+		 */
+		if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
+				pAC->Addr.Port[PortNumber].Exact[0].a)) {
+
+			pAC->Addr.Port[PortNumber].PreviousMacAddress =
+				pAC->Addr.Port[PortNumber].CurrentMacAddress;
+			pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+			/* Report address change to RLMT. */
+			Para.Para32[0] = PortNumber;
+			Para.Para32[0] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+		}
+
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
+		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
+#ifdef DEBUG
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+
+	/* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrOverride */
+
+
+/******************************************************************************
+ *
+ *	SkAddrPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ *	It calls either SkAddrXmacPromiscuousChange or
+ *	SkAddrGmacPromiscuousChange, according to the adapter in use.
+ *	The real work is done there.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	int ReturnCode;
+
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+	else {
+		ReturnCode = SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	int			i;
+	SK_BOOL		InexactModeBit;
+	SK_U8		Inexact;
+	SK_U8		HwInexact;
+	SK_FILTER64	HwInexactFilter;
+	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
+	int			CurPromMode = SK_PROM_MODE_NONE;
+
+	/* Read CurPromMode from Hardware. */
+	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+	if ((LoMode & XM_MD_ENA_PROM) != 0) {
+		/* Promiscuous mode! */
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+
+	for (Inexact = 0xFF, i = 0; i < 8; i++) {
+		Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+	}
+	if (Inexact == 0xFF) {
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+	}
+	else {
+		/* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+		InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
+
+		/* Read 64-bit hash register from XMAC */
+		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
+
+		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
+			HwInexact &= HwInexactFilter.Bytes[i];
+		}
+
+		if (InexactModeBit && (HwInexact == 0xFF)) {
+			CurPromMode |= SK_PROM_MODE_ALL_MC;
+		}
+	}
+
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */
+
+		/* Set all bits in 64-bit hash register. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
+		for (Inexact = 0, i = 0; i < 8; i++) {
+			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+		}
+		if (Inexact == 0) {
+			/* Disable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
+		}
+		else {
+			/* Set 64-bit hash register to InexactFilter. */
+			XM_OUTHASH(IoC, PortNumber, XM_HSM,
+				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+			/* Enable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+		}
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+		/* Set the MAC in Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
+		/* Clear Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrXmacPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	SK_U16		ReceiveControl;	/* GMAC Receive Control Register */
+	int		CurPromMode = SK_PROM_MODE_NONE;
+
+	/* Read CurPromMode from Hardware. */
+	GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
+
+	if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
+		/* Promiscuous mode! */
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+
+	if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
+		/* All Multicast mode! */
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+	}
+
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC */
+
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+
+	if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm. MC */
+
+		/* Set 64-bit hash register to InexactFilter. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+			&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+
+		/* Set the MAC to Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC */
+
+		/* Clear Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrGmacPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrSwap - swap address info
+ *
+ * Description:
+ *	This routine swaps address info of two ports.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrSwap(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	FromPortNumber,		/* Port1 Index */
+SK_U32	ToPortNumber)		/* Port2 Index */
+{
+	int			i;
+	SK_U8		Byte;
+	SK_MAC_ADDR	MacAddr;
+	SK_U32		DWord;
+
+	if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	/*
+	 * Swap:
+	 * - Exact Match Entries (GEnesis and Yukon)
+	 *   Yukon uses first entry for the logical MAC
+	 *   address (stored in the second GMAC register).
+	 * - FirstExactMatchRlmt (GEnesis only)
+	 * - NextExactMatchRlmt (GEnesis only)
+	 * - FirstExactMatchDrv (GEnesis only)
+	 * - NextExactMatchDrv (GEnesis only)
+	 * - 64-bit filter (InexactFilter)
+	 * - Promiscuous Mode
+	 * of ports.
+	 */
+
+	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
+		MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
+		pAC->Addr.Port[FromPortNumber].Exact[i] =
+			pAC->Addr.Port[ToPortNumber].Exact[i];
+		pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
+	}
+
+	for (i = 0; i < 8; i++) {
+		Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
+			pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
+	}
+
+	i = pAC->Addr.Port[FromPortNumber].PromMode;
+	pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
+	pAC->Addr.Port[ToPortNumber].PromMode = i;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
+		pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
+			pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
+
+		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
+		pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
+			pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
+		pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
+
+		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
+		pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
+			pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
+
+		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
+		pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
+			pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
+		pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
+	}
+
+	/* CAUTION: Solution works if only ports of one adapter are in use. */
+	for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
+		Net->NetNumber].NumPorts; i++) {
+		if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+			Port[i]->PortNumber == ToPortNumber) {
+			pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+				ActivePort = i;
+			/* 20001207 RA: Was "ToPortNumber;". */
+		}
+	}
+
+	(void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+	(void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
+
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrSwap */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skcsum.c b/drivers/net/sk98lin/skcsum.c
new file mode 100644
index 0000000..a5dc572
--- /dev/null
+++ b/drivers/net/sk98lin/skcsum.c
@@ -0,0 +1,929 @@
+/******************************************************************************
+ *
+ * Name:	skcsum.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 2002/04/11 10:02:04 $
+ * Purpose:	Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skcsum.c,v $
+ *	Revision 1.10  2002/04/11 10:02:04  rwahl
+ *	Fix in SkCsGetSendInfo():
+ *	- function did not return ProtocolFlags in every case.
+ *	- pseudo header csum calculated wrong for big endian.
+ *
+ *	Revision 1.9  2001/06/13 07:42:08  gklug
+ *	fix: NetNumber was wrong in CLEAR_STAT event
+ *	add: check for good NetNumber in Clear STAT
+ *
+ *	Revision 1.8  2001/02/06 11:15:36  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.7  2000/06/29 13:17:05  rassmann
+ *	Corrected reception of a packet with UDP checksum == 0 (which means there
+ *	is no UDP checksum).
+ *
+ *	Revision 1.6  2000/02/21 12:35:10  cgoos
+ *	Fixed license header comment.
+ *
+ *	Revision 1.5  2000/02/21 11:05:19  cgoos
+ *	Merged changes back to common source.
+ *	Fixed rx path for BIG ENDIAN architecture.
+ *
+ *	Revision 1.1  1999/07/26 15:28:12  mkarl
+ *	added return SKCS_STATUS_IP_CSUM_ERROR_UDP and
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester
+ *	changed from common source to windows specific source
+ *	therefore restarting with v1.0
+ *
+ *	Revision 1.3  1999/05/10 08:39:33  mkarl
+ *	prevent overflows in SKCS_HTON16
+ *	fixed a bug in pseudo header checksum calculation
+ *	added some comments
+ *
+ *	Revision 1.2  1998/10/22 11:53:28  swolf
+ *	Now using SK_DBG_MSG.
+ *
+ *	Revision 1.1  1998/09/01 15:35:41  swolf
+ *	initial revision
+ *
+ *	13-May-1998 sw	Created.
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#ifdef SK_USE_CSUM	/* Check if CSUM is to be used. */
+
+#ifndef lint
+static const char SysKonnectFileId[] = "@(#)"
+	"$Id: skcsum.c,v 1.10 2002/04/11 10:02:04 rwahl Exp $"
+	" (C) SysKonnect.";
+#endif	/* !lint */
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the "GEnesis" common module "CSUM".
+ *
+ * This module contains the code necessary to calculate, store, and verify the
+ * Internet Checksum of IP, TCP, and UDP frames.
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *	SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *	empty module.
+ *
+ *	SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *	definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *	external.
+ *
+ *	SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *	definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *	external.
+ *
+ * Include File Hierarchy:
+ *
+ *	"h/skdrv1st.h"
+ *	"h/skcsum.h"
+ *	 "h/sktypes.h"
+ *	 "h/skqueue.h"
+ *	"h/skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skcsum.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+/* The size of an Ethernet MAC header. */
+#define SKCS_ETHERNET_MAC_HEADER_SIZE			(6+6+2)
+
+/* The size of the used topology's MAC header. */
+#define	SKCS_MAC_HEADER_SIZE	SKCS_ETHERNET_MAC_HEADER_SIZE
+
+/* The size of the IP header without any option fields. */
+#define SKCS_IP_HEADER_SIZE						20
+
+/*
+ * Field offsets within the IP header.
+ */
+
+/* "Internet Header Version" and "Length". */
+#define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH	0
+
+/* "Total Length". */
+#define SKCS_OFS_IP_TOTAL_LENGTH				2
+
+/* "Flags" "Fragment Offset". */
+#define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET	6
+
+/* "Next Level Protocol" identifier. */
+#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL			9
+
+/* Source IP address. */
+#define SKCS_OFS_IP_SOURCE_ADDRESS				12
+
+/* Destination IP address. */
+#define SKCS_OFS_IP_DESTINATION_ADDRESS			16
+
+
+/*
+ * Field offsets within the UDP header.
+ */
+
+/* UDP checksum. */
+#define SKCS_OFS_UDP_CHECKSUM					6
+
+/* IP "Next Level Protocol" identifiers (see RFC 790). */
+#define SKCS_PROTO_ID_TCP		6	/* Transport Control Protocol */
+#define SKCS_PROTO_ID_UDP		17	/* User Datagram Protocol */
+
+/* IP "Don't Fragment" bit. */
+#define SKCS_IP_DONT_FRAGMENT	SKCS_HTON16(0x4000)
+
+/* Add a byte offset to a pointer. */
+#define SKCS_IDX(pPtr, Ofs)	((void *) ((char *) (pPtr) + (Ofs)))
+
+/*
+ * Macros that convert host to network representation and vice versa, i.e.
+ * little/big endian conversion on little endian machines only.
+ */
+#ifdef SK_LITTLE_ENDIAN
+#define SKCS_HTON16(Val16)	(((unsigned) (Val16) >> 8) | (((Val16) & 0xFF) << 8))
+#endif	/* SK_LITTLE_ENDIAN */
+#ifdef SK_BIG_ENDIAN
+#define SKCS_HTON16(Val16)	(Val16)
+#endif	/* SK_BIG_ENDIAN */
+#define SKCS_NTOH16(Val16)	SKCS_HTON16(Val16)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+/******************************************************************************
+ *
+ *	SkCsGetSendInfo - get checksum information for a send packet
+ *
+ * Description:
+ *	Get all checksum information necessary to send a TCP or UDP packet. The
+ *	function checks the IP header passed to it. If the high-level protocol
+ *	is either TCP or UDP the pseudo header checksum is calculated and
+ *	returned.
+ *
+ *	The function returns the total length of the IP header (including any
+ *	IP option fields), which is the same as the start offset of the IP data
+ *	which in turn is the start offset of the TCP or UDP header.
+ *
+ *	The function also returns the TCP or UDP pseudo header checksum, which
+ *	should be used as the start value for the hardware checksum calculation.
+ *	(Note that any actual pseudo header checksum can never calculate to
+ *	zero.)
+ *
+ * Note:
+ *	There is a bug in the ASIC which may lead to wrong checksums.
+ *
+ * Arguments:
+ *	pAc - A pointer to the adapter context struct.
+ *
+ *	pIpHeader - Pointer to IP header. Must be at least the IP header *not*
+ *	including any option fields, i.e. at least 20 bytes.
+ *
+ *	Note: This pointer will be used to address 8-, 16-, and 32-bit
+ *	variables with the respective alignment offsets relative to the pointer.
+ *	Thus, the pointer should point to a 32-bit aligned address. If the
+ *	target system cannot address 32-bit variables on non 32-bit aligned
+ *	addresses, then the pointer *must* point to a 32-bit aligned address.
+ *
+ *	pPacketInfo - A pointer to the packet information structure for this
+ *	packet. Before calling this SkCsGetSendInfo(), the following field must
+ *	be initialized:
+ *
+ *		ProtocolFlags - Initialize with any combination of
+ *		SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on
+ *		the protocols specified here. Any protocol(s) not specified
+ *		here will be ignored.
+ *
+ *		Note: Only one checksum can be calculated in hardware. Thus, if
+ *		SKCS_PROTO_IP is specified in the 'ProtocolFlags',
+ *		SkCsGetSendInfo() must calculate the IP header checksum in
+ *		software. It might be a better idea to have the calling
+ *		protocol stack calculate the IP header checksum.
+ *
+ * Returns: N/A
+ *	On return, the following fields in 'pPacketInfo' may or may not have
+ *	been filled with information, depending on the protocol(s) found in the
+ *	packet:
+ *
+ *	ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s)
+ *	that were both requested by the caller and actually found in the packet.
+ *	Protocol(s) not specified by the caller and/or not found in the packet
+ *	will have their respective SKCS_PROTO_XXX bit flags reset.
+ *
+ *	Note: For IP fragments, TCP and UDP packet information is ignored.
+ *
+ *	IpHeaderLength - The total length in bytes of the complete IP header
+ *	including any option fields is returned here. This is the start offset
+ *	of the IP data, i.e. the TCP or UDP header if present.
+ *
+ *	IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the
+ *	16-bit Internet Checksum of the IP header is returned here. This value
+ *	is to be stored into the packet's 'IP Header Checksum' field.
+ *
+ *	PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP
+ *	has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum
+ *	of the TCP or UDP pseudo header is returned here.
+ */
+#if 0
+void SkCsGetSendInfo(
+SK_AC				*pAc,			/* Adapter context struct. */
+void				*pIpHeader,		/* IP header. */
+SKCS_PACKET_INFO	*pPacketInfo,	/* Packet information struct. */
+int					NetNumber)		/* Net number */
+{
+	/* Internet Header Version found in IP header. */
+	unsigned InternetHeaderVersion;
+
+	/* Length of the IP header as found in IP header. */
+	unsigned IpHeaderLength;
+
+	/* Bit field specifiying the desired/found protocols. */
+	unsigned ProtocolFlags;
+
+	/* Next level protocol identifier found in IP header. */
+	unsigned NextLevelProtocol;
+
+	/* Length of IP data portion. */
+	unsigned IpDataLength;
+
+	/* TCP/UDP pseudo header checksum. */
+	unsigned long PseudoHeaderChecksum;
+
+	/* Pointer to next level protocol statistics structure. */
+	SKCS_PROTO_STATS *NextLevelProtoStats;
+
+	/* Temporary variable. */
+	unsigned Tmp;
+
+	Tmp = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
+
+	/* Get the Internet Header Version (IHV). */
+	/* Note: The IHV is stored in the upper four bits. */
+
+	InternetHeaderVersion = Tmp >> 4;
+
+	/* Check the Internet Header Version. */
+	/* Note: We currently only support IP version 4. */
+
+	if (InternetHeaderVersion != 4) {	/* IPv4? */
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
+			("Tx: Unknown Internet Header Version %u.\n",
+			InternetHeaderVersion));
+		pPacketInfo->ProtocolFlags = 0;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
+		return;
+	}
+
+	/* Get the IP header length (IHL). */
+	/*
+	 * Note: The IHL is stored in the lower four bits as the number of
+	 * 4-byte words.
+	 */
+
+	IpHeaderLength = (Tmp & 0xf) * 4;
+	pPacketInfo->IpHeaderLength = IpHeaderLength;
+
+	/* Check the IP header length. */
+
+	/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
+
+	if (IpHeaderLength < 5*4) {
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
+			("Tx: Invalid IP Header Length %u.\n", IpHeaderLength));
+		pPacketInfo->ProtocolFlags = 0;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
+		return;
+	}
+
+	/* This is an IPv4 frame with a header of valid length. */
+
+	pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++;
+
+	/* Check if we should calculate the IP header checksum. */
+
+	ProtocolFlags = pPacketInfo->ProtocolFlags;
+
+	if (ProtocolFlags & SKCS_PROTO_IP) {
+		pPacketInfo->IpHeaderChecksum =
+			SkCsCalculateChecksum(pIpHeader, IpHeaderLength);
+	}
+
+	/* Get the next level protocol identifier. */
+
+	NextLevelProtocol =
+		*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
+
+	/*
+	 * Check if this is a TCP or UDP frame and if we should calculate the
+	 * TCP/UDP pseudo header checksum.
+	 *
+	 * Also clear all protocol bit flags of protocols not present in the
+	 * frame.
+	 */
+
+	if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+		/* TCP/IP frame. */
+		ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP;
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
+	}
+	else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+		/* UDP/IP frame. */
+		ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP;
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
+	}
+	else {
+		/*
+		 * Either not a TCP or UDP frame and/or TCP/UDP processing not
+		 * specified.
+		 */
+		pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
+		return;
+	}
+
+	/* Check if this is an IP fragment. */
+
+	/*
+	 * Note: An IP fragment has a non-zero "Fragment Offset" field and/or
+	 * the "More Fragments" bit set. Thus, if both the "Fragment Offset"
+	 * and the "More Fragments" are zero, it is *not* a fragment. We can
+	 * easily check both at the same time since they are in the same 16-bit
+	 * word.
+	 */
+
+	if ((*(SK_U16 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
+		~SKCS_IP_DONT_FRAGMENT) != 0) {
+		/* IP fragment; ignore all other protocols. */
+		pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
+		NextLevelProtoStats->TxUnableCts++;
+		return;
+	}
+
+	/*
+	 * Calculate the TCP/UDP pseudo header checksum.
+	 */
+
+	/* Get total length of IP header and data. */
+
+	IpDataLength =
+		*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
+
+	/* Get length of IP data portion. */
+
+	IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
+
+	/* Calculate the sum of all pseudo header fields (16-bit). */
+
+	PseudoHeaderChecksum =
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
+		(unsigned long) SKCS_HTON16(NextLevelProtocol) +
+		(unsigned long) SKCS_HTON16(IpDataLength);
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
+
+	pPacketInfo->ProtocolFlags = ProtocolFlags;
+	NextLevelProtoStats->TxOkCts++;	/* Success. */
+}	/* SkCsGetSendInfo */
+
+
+/******************************************************************************
+ *
+ *	SkCsGetReceiveInfo - verify checksum information for a received packet
+ *
+ * Description:
+ *	Verify a received frame's checksum. The function returns a status code
+ *	reflecting the result of the verification.
+ *
+ * Note:
+ *	Before calling this function you have to verify that the frame is
+ *	not padded and Checksum1 and Checksum2 are bigger than 1.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context struct.
+ *
+ *	pIpHeader - Pointer to IP header. Must be at least the length in bytes
+ *	of the received IP header including any option fields. For UDP packets,
+ *	8 additional bytes are needed to access the UDP checksum.
+ *
+ *	Note: The actual length of the IP header is stored in the lower four
+ *	bits of the first octet of the IP header as the number of 4-byte words,
+ *	so it must be multiplied by four to get the length in bytes. Thus, the
+ *	maximum IP header length is 15 * 4 = 60 bytes.
+ *
+ *	Checksum1 - The first 16-bit Internet Checksum calculated by the
+ *	hardware starting at the offset returned by SkCsSetReceiveFlags().
+ *
+ *	Checksum2 - The second 16-bit Internet Checksum calculated by the
+ *	hardware starting at the offset returned by SkCsSetReceiveFlags().
+ *
+ * Returns:
+ *	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
+ *	SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *	SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *	SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *	SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *	SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *	SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ *	SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum.
+ *
+ *	Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values
+ *	returned here can be defined in some header file by the module using CSUM.
+ *	In this way, the calling module can assign return values for its own needs,
+ *	e.g. by assigning bit flags to the individual protocols.
+ */
+SKCS_STATUS SkCsGetReceiveInfo(
+SK_AC		*pAc,		/* Adapter context struct. */
+void		*pIpHeader,	/* IP header. */
+unsigned	Checksum1,	/* Hardware checksum 1. */
+unsigned	Checksum2,	/* Hardware checksum 2. */
+int			NetNumber)	/* Net number */
+{
+	/* Internet Header Version found in IP header. */
+	unsigned InternetHeaderVersion;
+
+	/* Length of the IP header as found in IP header. */
+	unsigned IpHeaderLength;
+
+	/* Length of IP data portion. */
+	unsigned IpDataLength;
+
+	/* IP header checksum. */
+	unsigned IpHeaderChecksum;
+
+	/* IP header options checksum, if any. */
+	unsigned IpOptionsChecksum;
+
+	/* IP data checksum, i.e. TCP/UDP checksum. */
+	unsigned IpDataChecksum;
+
+	/* Next level protocol identifier found in IP header. */
+	unsigned NextLevelProtocol;
+
+	/* The checksum of the "next level protocol", i.e. TCP or UDP. */
+	unsigned long NextLevelProtocolChecksum;
+
+	/* Pointer to next level protocol statistics structure. */
+	SKCS_PROTO_STATS *NextLevelProtoStats;
+
+	/* Temporary variable. */
+	unsigned Tmp;
+
+	Tmp = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
+
+	/* Get the Internet Header Version (IHV). */
+	/* Note: The IHV is stored in the upper four bits. */
+
+	InternetHeaderVersion = Tmp >> 4;
+
+	/* Check the Internet Header Version. */
+	/* Note: We currently only support IP version 4. */
+
+	if (InternetHeaderVersion != 4) {	/* IPv4? */
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
+			("Rx: Unknown Internet Header Version %u.\n",
+			InternetHeaderVersion));
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
+		return (SKCS_STATUS_UNKNOWN_IP_VERSION);
+	}
+
+	/* Get the IP header length (IHL). */
+	/*
+	 * Note: The IHL is stored in the lower four bits as the number of
+	 * 4-byte words.
+	 */
+
+	IpHeaderLength = (Tmp & 0xf) * 4;
+
+	/* Check the IP header length. */
+
+	/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
+
+	if (IpHeaderLength < 5*4) {
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
+			("Rx: Invalid IP Header Length %u.\n", IpHeaderLength));
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
+		return (SKCS_STATUS_IP_CSUM_ERROR);
+	}
+
+	/* This is an IPv4 frame with a header of valid length. */
+
+	/* Get the IP header and data checksum. */
+
+	IpDataChecksum = Checksum2;
+
+	/*
+	 * The IP header checksum is calculated as follows:
+	 *
+	 *	IpHeaderChecksum = Checksum1 - Checksum2
+	 */
+
+	SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2);
+
+	/* Check if any IP header options. */
+
+	if (IpHeaderLength > SKCS_IP_HEADER_SIZE) {
+
+		/* Get the IP options checksum. */
+
+		IpOptionsChecksum = SkCsCalculateChecksum(
+			SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE),
+			IpHeaderLength - SKCS_IP_HEADER_SIZE);
+
+		/* Adjust the IP header and IP data checksums. */
+
+		SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum);
+
+		SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum);
+	}
+
+	/*
+	 * Check if the IP header checksum is ok.
+	 *
+	 * NOTE: We must check the IP header checksum even if the caller just wants
+	 * us to check upper-layer checksums, because we cannot do any further
+	 * processing of the packet without a valid IP checksum.
+	 */
+
+	/* Get the next level protocol identifier. */
+
+	NextLevelProtocol = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
+
+	if (IpHeaderChecksum != 0xFFFF) {
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
+		/* the NDIS tester wants to know the upper level protocol too */
+		if (NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+			return(SKCS_STATUS_IP_CSUM_ERROR_TCP);
+		}
+		else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+			return(SKCS_STATUS_IP_CSUM_ERROR_UDP);
+		}
+		return (SKCS_STATUS_IP_CSUM_ERROR);
+	}
+
+	/*
+	 * Check if this is a TCP or UDP frame and if we should calculate the
+	 * TCP/UDP pseudo header checksum.
+	 *
+	 * Also clear all protocol bit flags of protocols not present in the
+	 * frame.
+	 */
+
+	if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+		/* TCP/IP frame. */
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
+	}
+	else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+		/* UDP/IP frame. */
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
+	}
+	else {
+		/*
+		 * Either not a TCP or UDP frame and/or TCP/UDP processing not
+		 * specified.
+		 */
+		return (SKCS_STATUS_IP_CSUM_OK);
+	}
+
+	/* Check if this is an IP fragment. */
+
+	/*
+	 * Note: An IP fragment has a non-zero "Fragment Offset" field and/or
+	 * the "More Fragments" bit set. Thus, if both the "Fragment Offset"
+	 * and the "More Fragments" are zero, it is *not* a fragment. We can
+	 * easily check both at the same time since they are in the same 16-bit
+	 * word.
+	 */
+
+	if ((*(SK_U16 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
+		~SKCS_IP_DONT_FRAGMENT) != 0) {
+		/* IP fragment; ignore all other protocols. */
+		NextLevelProtoStats->RxUnableCts++;
+		return (SKCS_STATUS_IP_FRAGMENT);
+	}
+
+	/*
+	 * 08-May-2000 ra
+	 *
+	 * From RFC 768 (UDP)
+	 * If the computed checksum is zero, it is transmitted as all ones (the
+	 * equivalent in one's complement arithmetic).  An all zero transmitted
+	 * checksum value means that the transmitter generated no checksum (for
+	 * debugging or for higher level protocols that don't care).
+	 */
+
+	if (NextLevelProtocol == SKCS_PROTO_ID_UDP &&
+		*(SK_U16*)SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) {
+
+		NextLevelProtoStats->RxOkCts++;
+
+		return (SKCS_STATUS_IP_CSUM_OK_NO_UDP);
+	}
+
+	/*
+	 * Calculate the TCP/UDP checksum.
+	 */
+
+	/* Get total length of IP header and data. */
+
+	IpDataLength =
+		*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
+
+	/* Get length of IP data portion. */
+
+	IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
+
+	NextLevelProtocolChecksum =
+
+		/* Calculate the pseudo header checksum. */
+
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
+		(unsigned long) SKCS_HTON16(NextLevelProtocol) +
+		(unsigned long) SKCS_HTON16(IpDataLength) +
+
+		/* Add the TCP/UDP header checksum. */
+
+		(unsigned long) IpDataChecksum;
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
+
+	/* Check if the TCP/UDP checksum is ok. */
+
+	if ((unsigned) NextLevelProtocolChecksum == 0xFFFF) {
+
+		/* TCP/UDP checksum ok. */
+
+		NextLevelProtoStats->RxOkCts++;
+
+		return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
+			SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK);
+	}
+
+	/* TCP/UDP checksum error. */
+
+	NextLevelProtoStats->RxErrCts++;
+
+	return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
+		SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR);
+}	/* SkCsGetReceiveInfo */
+#endif
+
+
+/******************************************************************************
+ *
+ *	SkCsSetReceiveFlags - set checksum receive flags
+ *
+ * Description:
+ *	Use this function to set the various receive flags. According to the
+ *	protocol flags set by the caller, the start offsets within received
+ *	packets of the two hardware checksums are returned. These offsets must
+ *	be stored in all receive descriptors.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context struct.
+ *
+ *	ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols
+ *	for which the caller wants checksum information on received frames.
+ *
+ *	pChecksum1Offset - The start offset of the first receive descriptor
+ *	hardware checksum to be calculated for received frames is returned
+ *	here.
+ *
+ *	pChecksum2Offset - The start offset of the second receive descriptor
+ *	hardware checksum to be calculated for received frames is returned
+ *	here.
+ *
+ * Returns: N/A
+ *	Returns the two hardware checksum start offsets.
+ */
+void SkCsSetReceiveFlags(
+SK_AC		*pAc,				/* Adapter context struct. */
+unsigned	ReceiveFlags,		/* New receive flags. */
+unsigned	*pChecksum1Offset,	/* Offset for hardware checksum 1. */
+unsigned	*pChecksum2Offset,	/* Offset for hardware checksum 2. */
+int			NetNumber)
+{
+	/* Save the receive flags. */
+
+	pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags;
+
+	/* First checksum start offset is the IP header. */
+	*pChecksum1Offset = SKCS_MAC_HEADER_SIZE;
+
+	/*
+	 * Second checksum start offset is the IP data. Note that this may vary
+	 * if there are any IP header options in the actual packet.
+	 */
+	*pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE;
+}	/* SkCsSetReceiveFlags */
+
+#ifndef SkCsCalculateChecksum
+
+/******************************************************************************
+ *
+ *	SkCsCalculateChecksum - calculate checksum for specified data
+ *
+ * Description:
+ *	Calculate and return the 16-bit Internet Checksum for the specified
+ *	data.
+ *
+ * Arguments:
+ *	pData - Pointer to data for which the checksum shall be calculated.
+ *	Note: The pointer should be aligned on a 16-bit boundary.
+ *
+ *	Length - Length in bytes of data to checksum.
+ *
+ * Returns:
+ *	The 16-bit Internet Checksum for the specified data.
+ *
+ *	Note: The checksum is calculated in the machine's natural byte order,
+ *	i.e. little vs. big endian. Thus, the resulting checksum is different
+ *	for the same input data on little and big endian machines.
+ *
+ *	However, when written back to the network packet, the byte order is
+ *	always in correct network order.
+ */
+unsigned SkCsCalculateChecksum(
+void		*pData,		/* Data to checksum. */
+unsigned	Length)		/* Length of data. */
+{
+	SK_U16 *pU16;		/* Pointer to the data as 16-bit words. */
+	unsigned long Checksum;	/* Checksum; must be at least 32 bits. */
+
+	/* Sum up all 16-bit words. */
+
+	pU16 = (SK_U16 *) pData;
+	for (Checksum = 0; Length > 1; Length -= 2) {
+		Checksum += *pU16++;
+	}
+
+	/* If this is an odd number of bytes, add-in the last byte. */
+
+	if (Length > 0) {
+#ifdef SK_BIG_ENDIAN
+		/* Add the last byte as the high byte. */
+		Checksum += ((unsigned) *(SK_U8 *) pU16) << 8;
+#else	/* !SK_BIG_ENDIAN */
+		/* Add the last byte as the low byte. */
+		Checksum += *(SK_U8 *) pU16;
+#endif	/* !SK_BIG_ENDIAN */
+	}
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(Checksum, Checksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(Checksum, Checksum, 0);
+
+	/* Note: All bits beyond the 16-bit limit are now zero. */
+
+	return ((unsigned) Checksum);
+}	/* SkCsCalculateChecksum */
+
+#endif /* SkCsCalculateChecksum */
+
+/******************************************************************************
+ *
+ *	SkCsEvent - the CSUM event dispatcher
+ *
+ * Description:
+ *	This is the event handler for the CSUM module.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context.
+ *
+ *	Ioc - I/O context.
+ *
+ *	Event -	 Event id.
+ *
+ *	Param - Event dependent parameter.
+ *
+ * Returns:
+ *	The 16-bit Internet Checksum for the specified data.
+ *
+ *	Note: The checksum is calculated in the machine's natural byte order,
+ *	i.e. little vs. big endian. Thus, the resulting checksum is different
+ *	for the same input data on little and big endian machines.
+ *
+ *	However, when written back to the network packet, the byte order is
+ *	always in correct network order.
+ */
+int SkCsEvent(
+SK_AC		*pAc,	/* Pointer to adapter context. */
+SK_IOC		Ioc,	/* I/O context. */
+SK_U32		Event,	/* Event id. */
+SK_EVPARA	Param)	/* Event dependent parameter. */
+{
+	int ProtoIndex;
+	int	NetNumber;
+
+	switch (Event) {
+	/*
+	 * Clear protocol statistics.
+	 *
+	 * Param - Protocol index, or -1 for all protocols.
+	 *		 - Net number.
+	 */
+	case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
+
+		ProtoIndex = (int)Param.Para32[1];
+		NetNumber = (int)Param.Para32[0];
+		if (ProtoIndex < 0) {	/* Clear for all protocols. */
+			if (NetNumber >= 0) {
+				memset(&pAc->Csum.ProtoStats[NetNumber][0], 0,
+					sizeof(pAc->Csum.ProtoStats[NetNumber]));
+			}
+		}
+		else {					/* Clear for individual protocol. */
+			memset(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0,
+				sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex]));
+		}
+		break;
+	default:
+		break;
+	}
+	return (0);	/* Success. */
+}	/* SkCsEvent */
+
+#endif	/* SK_USE_CSUM */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
new file mode 100644
index 0000000..61a6094
--- /dev/null
+++ b/drivers/net/sk98lin/skge.c
@@ -0,0 +1,4864 @@
+/******************************************************************************
+ *
+ * Name:    skge.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.46 $
+ * Date:       	$Date: 2003/02/25 14:16:36 $
+ * Purpose:	The main driver source module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	Driver for SysKonnect Gigabit Ethernet Server Adapters:
+ *
+ *	SK-9871 (single link 1000Base-ZX)
+ *	SK-9872 (dual link   1000Base-ZX)
+ *	SK-9861 (single link 1000Base-SX, VF45 Volition Plug)
+ *	SK-9862 (dual link   1000Base-SX, VF45 Volition Plug)
+ *	SK-9841 (single link 1000Base-LX)
+ *	SK-9842 (dual link   1000Base-LX)
+ *	SK-9843 (single link 1000Base-SX)
+ *	SK-9844 (dual link   1000Base-SX)
+ *	SK-9821 (single link 1000Base-T)
+ *	SK-9822 (dual link   1000Base-T)
+ *	SK-9881 (single link 1000Base-SX V2 LC)
+ *	SK-9871 (single link 1000Base-ZX V2)
+ *	SK-9861 (single link 1000Base-SX V2, VF45 Volition Plug)
+ *	SK-9841 (single link 1000Base-LX V2)
+ *	SK-9843 (single link 1000Base-SX V2)
+ *	SK-9821 (single link 1000Base-T V2)
+ *
+ *	Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and
+ *	SysKonnects GEnesis Solaris driver
+ *	Author: Christoph Goos (cgoos@syskonnect.de)
+ *	        Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *	Address all question to: linux@syskonnect.de
+ *
+ *	The technical manual for the adapters is available from SysKonnect's
+ *	web pages: www.syskonnect.com
+ *	Goto "Support" and search Knowledge Base for "manual".
+ *
+ *	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: skge.c,v $
+ *	Revision 1.46  2003/02/25 14:16:36  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.45  2003/02/25 13:25:55  mlindner
+ *	Add: Performance improvements
+ *	Add: Support for various vendors
+ *	Fix: Init function
+ *
+ *	Revision 1.44  2003/01/09 09:25:26  mlindner
+ *	Fix: Remove useless init_module/cleanup_module forward declarations
+ *
+ *	Revision 1.43  2002/11/29 08:42:41  mlindner
+ *	Fix: Boot message
+ *
+ *	Revision 1.42  2002/11/28 13:30:23  mlindner
+ *	Add: New frame check
+ *
+ *	Revision 1.41  2002/11/27 13:55:18  mlindner
+ *	Fix: Drop wrong csum packets
+ *	Fix: Initialize proc_entry after hw check
+ *
+ *	Revision 1.40  2002/10/31 07:50:37  tschilli
+ *	Function SkGeInitAssignRamToQueues() from common module inserted.
+ *	Autonegotiation is set to ON for all adapters.
+ *	LinkSpeedUsed is used in link up status report.
+ *	Role parameter will show up for 1000 Mbps links only.
+ *	GetConfiguration() inserted after init level 1 in SkGeChangeMtu().
+ *	All return values of SkGeInit() and SkGeInitPort() are checked.
+ *
+ *	Revision 1.39  2002/10/02 12:56:05  mlindner
+ *	Add: Support for Yukon
+ *	Add: Support for ZEROCOPY, scatter-gather and hw checksum
+ *	Add: New transmit ring function (use SG and TCP/UDP hardware checksumming)
+ *	Add: New init function
+ *	Add: Speed check and setup
+ *	Add: Merge source for kernel 2.2.x and 2.4.x
+ *	Add: Opcode check for tcp
+ *	Add: Frame length check
+ *	Fix: Transmit complete interrupt
+ *	Fix: Interrupt moderation
+ *
+ *	Revision 1.29.2.13  2002/01/14 12:44:52  mlindner
+ *	Fix: Rlmt modes
+ *
+ *	Revision 1.29.2.12  2001/12/07 12:06:18  mlindner
+ *	Fix: malloc -> slab changes
+ *
+ *	Revision 1.29.2.11  2001/12/06 15:19:20  mlindner
+ *	Add: DMA attributes
+ *	Fix: Module initialisation
+ *	Fix: pci_map_single and pci_unmap_single replaced
+ *
+ *	Revision 1.29.2.10  2001/12/06 09:56:50  mlindner
+ *	Corrected some printk's
+ *
+ *	Revision 1.29.2.9  2001/09/05 12:15:34  mlindner
+ *	Add: LBFO Changes
+ *	Fix: Counter Errors (Jumbo == to long errors)
+ *	Fix: Changed pAC->PciDev declaration
+ *	Fix: too short counters
+ *
+ *	Revision 1.29.2.8  2001/06/25 12:10:44  mlindner
+ *	fix: ReceiveIrq() changed.
+ *
+ *	Revision 1.29.2.7  2001/06/25 08:07:05  mlindner
+ *	fix: RLMT locking in ReceiveIrq() changed.
+ *
+ *	Revision 1.29.2.6  2001/05/21 07:59:29  mlindner
+ *	fix: MTU init problems
+ *
+ *	Revision 1.29.2.5  2001/05/08 11:25:08  mlindner
+ *	fix: removed VLAN error message
+ *
+ *	Revision 1.29.2.4  2001/05/04 13:31:43  gklug
+ *	fix: do not handle eth_copy on bad fragments received.
+ *
+ *	Revision 1.29.2.3  2001/04/23 08:06:43  mlindner
+ *	Fix: error handling
+ *
+ *	Revision 1.29.2.2  2001/03/15 12:04:54  mlindner
+ *	Fixed memory problem
+ *
+ *	Revision 1.29.2.1  2001/03/12 16:41:44  mlindner
+ *	add: procfs function
+ *	add: dual-net function
+ *	add: RLMT networks
+ *	add: extended PNMI features
+ *
+ *	Kernel 2.4.x specific:
+ *	Revision 1.xx  2000/09/12 13:31:56  cgoos
+ *	Fixed missign "dev=NULL in skge_probe.
+ *	Added counting for jumbo frames (corrects error statistic).
+ *	Removed VLAN tag check (enables VLAN support).
+ *
+ *	Kernel 2.2.x specific:
+ *	Revision 1.29  2000/02/21 13:31:56  cgoos
+ *	Fixed "unused" warning for UltraSPARC change.
+ *
+ *	Partially kernel 2.2.x specific:
+ *	Revision 1.28  2000/02/21 10:32:36  cgoos
+ *	Added fixes for UltraSPARC.
+ *	Now printing RlmtMode and PrefPort setting at startup.
+ *	Changed XmitFrame return value.
+ *	Fixed rx checksum calculation for BIG ENDIAN systems.
+ *	Fixed rx jumbo frames counted as ierrors.
+ *
+ *
+ *	Revision 1.27  1999/11/25 09:06:28  cgoos
+ *	Changed base_addr to unsigned long.
+ *
+ *	Revision 1.26  1999/11/22 13:29:16  cgoos
+ *	Changed license header to GPL.
+ *	Changes for inclusion in linux kernel (2.2.13).
+ *	Removed 2.0.x defines.
+ *	Changed SkGeProbe to skge_probe.
+ *	Added checks in SkGeIoctl.
+ *
+ *	Revision 1.25  1999/10/07 14:47:52  cgoos
+ *	Changed 984x to 98xx.
+ *
+ *	Revision 1.24  1999/09/30 07:21:01  cgoos
+ *	Removed SK_RLMT_SLOW_LOOKAHEAD option.
+ *	Giving spanning tree packets also to OS now.
+ *
+ *	Revision 1.23  1999/09/29 07:36:50  cgoos
+ *	Changed assignment for IsBc/IsMc.
+ *
+ *	Revision 1.22  1999/09/28 12:57:09  cgoos
+ *	Added CheckQueue also to Single-Port-ISR.
+ *
+ *	Revision 1.21  1999/09/28 12:42:41  cgoos
+ *	Changed parameter strings for RlmtMode.
+ *
+ *	Revision 1.20  1999/09/28 12:37:57  cgoos
+ *	Added CheckQueue for fast delivery of RLMT frames.
+ *
+ *	Revision 1.19  1999/09/16 07:57:25  cgoos
+ *	Copperfield changes.
+ *
+ *	Revision 1.18  1999/09/03 13:06:30  cgoos
+ *	Fixed RlmtMode=CheckSeg bug: wrong DEV_KFREE_SKB in RLMT_SEND caused
+ *	double allocated skb's.
+ *	FrameStat in ReceiveIrq was accessed via wrong Rxd.
+ *	Queue size for async. standby Tx queue was zero.
+ *	FillRxLimit of 0 could cause problems with ReQueue, changed to 1.
+ *	Removed debug output of checksum statistic.
+ *
+ *	Revision 1.17  1999/08/11 13:55:27  cgoos
+ *	Transmit descriptor polling was not reenabled after SkGePortInit.
+ *
+ *	Revision 1.16  1999/07/27 15:17:29  cgoos
+ *	Added some "\n" in output strings (removed while debuging...).
+ *
+ *	Revision 1.15  1999/07/23 12:09:30  cgoos
+ *	Performance optimization, rx checksumming, large frame support.
+ *
+ *	Revision 1.14  1999/07/14 11:26:27  cgoos
+ *	Removed Link LED settings (now in RLMT).
+ *	Added status output at NET UP.
+ *	Fixed SMP problems with Tx and SWITCH running in parallel.
+ *	Fixed return code problem at RLMT_SEND event.
+ *
+ *	Revision 1.13  1999/04/07 10:11:42  cgoos
+ *	Fixed Single Port problems.
+ *	Fixed Multi-Adapter problems.
+ *	Always display startup string.
+ *
+ *	Revision 1.12  1999/03/29 12:26:37  cgoos
+ *	Reversed locking to fine granularity.
+ *	Fixed skb double alloc problem (caused by incorrect xmit return code).
+ *	Enhanced function descriptions.
+ *
+ *	Revision 1.11  1999/03/15 13:10:51  cgoos
+ *	Changed device identifier in output string to ethX.
+ *
+ *	Revision 1.10  1999/03/15 12:12:34  cgoos
+ *	Changed copyright notice.
+ *
+ *	Revision 1.9  1999/03/15 12:10:17  cgoos
+ *	Changed locking to one driver lock.
+ *	Added check of SK_AC-size (for consistency with library).
+ *
+ *	Revision 1.8  1999/03/08 11:44:02  cgoos
+ *	Fixed missing dev->tbusy in SkGeXmit.
+ *	Changed large frame (jumbo) buffer number.
+ *	Added copying of short frames.
+ *
+ *	Revision 1.7  1999/03/04 13:26:57  cgoos
+ *	Fixed spinlock calls for SMP.
+ *
+ *	Revision 1.6  1999/03/02 09:53:51  cgoos
+ *	Added descriptor revertion for big endian machines.
+ *
+ *	Revision 1.5  1999/03/01 08:50:59  cgoos
+ *	Fixed SkGeChangeMtu.
+ *	Fixed pci config space accesses.
+ *
+ *	Revision 1.4  1999/02/18 15:48:44  cgoos
+ *	Corrected some printk's.
+ *
+ *	Revision 1.3  1999/02/18 12:45:55  cgoos
+ *	Changed SK_MAX_CARD_PARAM to default 16
+ *
+ *	Revision 1.2  1999/02/18 10:55:32  cgoos
+ *	Removed SkGeDrvTimeStamp function.
+ *	Printing "ethX:" before adapter type at adapter init.
+ *
+ *
+ *	10-Feb-1999 cg	Created, based on Linux' acenic.c, 3c59x.c and
+ *			SysKonnects GEnesis Solaris driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Possible compiler options (#define xxx / -Dxxx):
+ *
+ *	debugging can be enable by changing SK_DEBUG_CHKMOD and
+ *	SK_DEBUG_CHKCAT in makefile (described there).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ *	This is the main module of the Linux GE driver.
+ *
+ *	All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h
+ *	are part of SysKonnect's COMMON MODULES for the SK-98xx adapters.
+ *	Those are used for drivers on multiple OS', so some thing may seem
+ *	unnecessary complicated on Linux. Please do not try to 'clean up'
+ *	them without VERY good reasons, because this will make it more
+ *	difficult to keep the Linux driver in synchronisation with the
+ *	other versions.
+ *
+ * Include file hierarchy:
+ *
+ *	<linux/module.h>
+ *
+ *	"h/skdrv1st.h"
+ *		<linux/version.h>
+ *		<linux/types.h>
+ *		<linux/kernel.h>
+ *		<linux/string.h>
+ *		<linux/errno.h>
+ *		<linux/ioport.h>
+ *		<linux/slab.h>
+ *		<linux/interrupt.h>
+ *		<linux/pci.h>
+ *		<asm/byteorder.h>
+ *		<asm/bitops.h>
+ *		<asm/io.h>
+ *		<linux/netdevice.h>
+ *		<linux/etherdevice.h>
+ *		<linux/skbuff.h>
+ *	    those three depending on kernel version used:
+ *		<linux/bios32.h>
+ *		<linux/init.h>
+ *		<asm/uaccess.h>
+ *		<net/checksum.h>
+ *
+ *		"h/skerror.h"
+ *		"h/skdebug.h"
+ *		"h/sktypes.h"
+ *		"h/lm80.h"
+ *		"h/xmac_ii.h"
+ *
+ *      "h/skdrv2nd.h"
+ *		"h/skqueue.h"
+ *		"h/skgehwt.h"
+ *		"h/sktimer.h"
+ *		"h/ski2c.h"
+ *		"h/skgepnmi.h"
+ *		"h/skvpd.h"
+ *		"h/skgehw.h"
+ *		"h/skgeinit.h"
+ *		"h/skaddr.h"
+ *		"h/skgesirq.h"
+ *		"h/skcsum.h"
+ *		"h/skrlmt.h"
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#include	"h/skversion.h"
+#if 0
+#include	<linux/module.h>
+#include	<linux/init.h>
+#include 	<linux/proc_fs.h>
+#endif
+#include	"h/skdrv1st.h"
+#include	"h/skdrv2nd.h"
+
+
+/* defines ******************************************************************/
+/* for debuging on x86 only */
+/* #define BREAKPOINT() asm(" int $3"); */
+
+/* use the scatter-gather functionality with sendfile() */
+#if 0
+#define SK_ZEROCOPY
+#endif
+
+/* use of a transmit complete interrupt */
+#define USE_TX_COMPLETE
+
+/* use interrupt moderation (for tx complete only) */
+#define USE_INT_MOD
+#define INTS_PER_SEC	1000
+
+/*
+ * threshold for copying small receive frames
+ * set to 0 to avoid copying, set to 9001 to copy all frames
+ */
+#define SK_COPY_THRESHOLD	50
+
+/* number of adapters that can be configured via command line params */
+#define SK_MAX_CARD_PARAM	16
+
+
+/*
+ * use those defines for a compile-in version of the driver instead
+ * of command line parameters
+ */
+/* #define LINK_SPEED_A	{"Auto", }		*/
+/* #define LINK_SPEED_B	{"Auto", }		*/
+/* #define AUTO_NEG_A	{"Sense", }		*/
+/* #define AUTO_NEG_B	{"Sense", }		*/
+/* #define DUP_CAP_A	{"Both", }		*/
+/* #define DUP_CAP_B	{"Both", }		*/
+/* #define FLOW_CTRL_A	{"SymOrRem", }		*/
+/* #define FLOW_CTRL_B	{"SymOrRem", }		*/
+/* #define ROLE_A	{"Auto", }		*/
+/* #define ROLE_B	{"Auto", }		*/
+/* #define PREF_PORT	{"A", }			*/
+/* #define RLMT_MODE	{"CheckLinkState", }	*/
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
+
+/* function prototypes ******************************************************/
+static void	FreeResources(struct SK_NET_DEVICE *dev);
+static int	SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC);
+static SK_BOOL	BoardAllocMem(SK_AC *pAC);
+static void	BoardFreeMem(SK_AC *pAC);
+static void	BoardInitMem(SK_AC *pAC);
+static void	SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**,
+			int*, SK_BOOL);
+
+#if 0
+static void	SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
+static void	SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
+static int	SkGeOpen(struct SK_NET_DEVICE *dev);
+static int	SkGeClose(struct SK_NET_DEVICE *dev);
+static int	SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+static int	SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p);
+static void	SkGeSetRxMode(struct SK_NET_DEVICE *dev);
+static struct	net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
+static int	SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
+#else
+void	SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
+void	SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
+int	SkGeOpen(struct SK_NET_DEVICE *dev);
+int	SkGeClose(struct SK_NET_DEVICE *dev);
+int	SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+#endif
+static void	GetConfiguration(SK_AC*);
+static void	ProductStr(SK_AC*);
+static int	XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
+static void	FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
+static void	FillRxRing(SK_AC*, RX_PORT*);
+static SK_BOOL	FillRxDescriptor(SK_AC*, RX_PORT*);
+#if 0
+static void	ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+#else
+void	ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+#endif
+static void ClearAndStartRx(SK_AC*, int);
+static void	ClearTxIrq(SK_AC*, int, int);
+static void	ClearRxRing(SK_AC*, RX_PORT*);
+static void	ClearTxRing(SK_AC*, TX_PORT*);
+#if 0
+static void	SetQueueSizes(SK_AC	*pAC);
+
+static int	SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu);
+#endif
+static void	PortReInitBmu(SK_AC*, int);
+#if 0
+static int	SkGeIocMib(DEV_NET*, unsigned int, int);
+static int	XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*);
+#endif
+
+/*Extern */
+
+/* external Proc function */
+extern int proc_read(
+	char	*buffer,
+	char	**buffer_location,
+	off_t	offset,
+	int		buffer_length,
+	int		*eof,
+	void	*data);
+
+#ifdef DEBUG
+static void	DumpMsg(struct sk_buff*, char*);
+static void	DumpData(char*, int);
+static void	DumpLong(char*, int);
+#endif
+void dump_frag( SK_U8 *data, int length);
+
+/* global variables *********************************************************/
+#if 0
+static const char *BootString = BOOT_STRING;
+#endif
+struct SK_NET_DEVICE *SkGeRootDev = NULL;
+static int probed __initdata = 0;
+
+/* local variables **********************************************************/
+static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
+
+
+/* local variables **********************************************************/
+const char SK_Root_Dir_entry[8];
+
+#if 0
+static struct proc_dir_entry	*pSkRootDir;
+#endif
+
+
+static struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_3COM, 0x1700},
+	{PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE},
+	{PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU},
+	{}
+};
+
+
+/*****************************************************************************
+ *
+ * 	skge_probe - find all SK-98xx adapters
+ *
+ * Description:
+ *	This function scans the PCI bus for SK-98xx adapters. Resources for
+ *	each adapter are allocated and the adapter is brought into Init 1
+ *	state.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+#if 0
+static int __init skge_probe (void)
+#else
+int skge_probe (struct eth_device ** ret_dev)
+#endif
+{
+#if 0
+	int			proc_root_initialized = 0;
+#endif
+	int			boards_found = 0;
+#if 0
+	int			vendor_flag = SK_FALSE;
+#endif
+	SK_AC			*pAC;
+	DEV_NET			*pNet = NULL;
+#if 0
+	struct proc_dir_entry	*pProcFile;
+	struct pci_dev	*pdev = NULL;
+	unsigned long		base_address;
+#else
+	u32			base_address;
+#endif
+	struct SK_NET_DEVICE *dev = NULL;
+#if 0
+	SK_BOOL DeviceFound = SK_FALSE;
+#endif
+	SK_BOOL BootStringCount = SK_FALSE;
+#if 1
+	pci_dev_t devno;
+#endif
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	if (!pci_present())		/* is PCI support present? */
+		return -ENODEV;
+
+#if 0
+		while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)))
+#else
+		while((devno = pci_find_devices (supported, boards_found)) >= 0)
+#endif
+		{
+
+		dev = NULL;
+		pNet = NULL;
+
+
+#if 0
+		SK_PCI_ISCOMPLIANT(vendor_flag, pdev);
+		if (!vendor_flag)
+			continue;
+#endif
+
+/*		if ((pdev->vendor != PCI_VENDOR_ID_SYSKONNECT) &&
+			((pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) ||
+			(pdev->device != PCI_DEVICE_ID_SYSKONNECT_YU))){
+			continue;
+		}
+*/
+#if 0
+		/* Configure DMA attributes. */
+		if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
+			pci_set_dma_mask(pdev, (u64) 0xffffffff))
+			continue;
+#endif
+
+
+#if 0
+		if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == NULL) {
+			printk(KERN_ERR "Unable to allocate etherdev "
+			       "structure!\n");
+			break;
+		}
+#else
+		dev = malloc (sizeof *dev);
+		memset(dev, 0, sizeof(*dev));
+		dev->priv = malloc(sizeof(DEV_NET));
+#endif
+
+		if (dev->priv == NULL) {
+			printk(KERN_ERR "Unable to allocate adapter "
+			       "structure!\n");
+			break;
+		}
+
+		pNet = dev->priv;
+		pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+		if (pNet->pAC == NULL){
+			kfree(dev->priv);
+			printk(KERN_ERR "Unable to allocate adapter "
+			       "structure!\n");
+			break;
+		}
+
+		/* Print message */
+		if (!BootStringCount) {
+			/* set display flag to TRUE so that */
+			/* we only display this string ONCE */
+			BootStringCount = SK_TRUE;
+#ifdef SK98_INFO
+			printk("%s\n", BootString);
+#endif
+		}
+
+		memset(pNet->pAC, 0, sizeof(SK_AC));
+		pAC = pNet->pAC;
+#if 0
+		pAC->PciDev = pdev;
+		pAC->PciDevId = pdev->device;
+		pAC->dev[0] = dev;
+		pAC->dev[1] = dev;
+#else
+		pAC->PciDev = devno;
+		ret_dev[0] = pAC->dev[0] = dev;
+		ret_dev[1] = pAC->dev[1] = dev;
+#endif
+		sprintf(pAC->Name, "SysKonnect SK-98xx");
+		pAC->CheckQueue = SK_FALSE;
+
+		pNet->Mtu = 1500;
+		pNet->Up = 0;
+#if 0
+		dev->irq = pdev->irq;
+
+		dev->open =		&SkGeOpen;
+		dev->stop =		&SkGeClose;
+		dev->hard_start_xmit =	&SkGeXmit;
+		dev->get_stats =	&SkGeStats;
+		dev->set_multicast_list = &SkGeSetRxMode;
+		dev->set_mac_address =	&SkGeSetMacAddr;
+		dev->do_ioctl =		&SkGeIoctl;
+		dev->change_mtu =	&SkGeChangeMtu;
+		dev->flags &= 		~IFF_RUNNING;
+#endif
+
+#ifdef SK_ZEROCOPY
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+			/* Use only if yukon hardware */
+			/* SK and ZEROCOPY - fly baby... */
+			dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+		}
+#endif
+
+#if 0
+		/*
+		 * Dummy value.
+		 */
+		dev->base_addr = 42;
+		pci_set_master(pdev);
+
+		pci_set_master(pdev);
+		base_address = pci_resource_start (pdev, 0);
+#else
+		pci_write_config_dword(devno,
+				       PCI_COMMAND,
+				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+		pci_read_config_dword (devno, PCI_BASE_ADDRESS_0,
+				       &base_address);
+#endif
+
+#ifdef SK_BIG_ENDIAN
+		/*
+		 * On big endian machines, we use the adapter's aibility of
+		 * reading the descriptors as big endian.
+		 */
+		{
+		SK_U32		our2;
+			SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2);
+			our2 |= PCI_REV_DESC;
+			SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
+		}
+#endif
+
+		/*
+		 * Remap the regs into kernel space.
+		 */
+#if 0
+		pAC->IoBase = (char*)ioremap(base_address, 0x4000);
+#else
+		pAC->IoBase = (char*)pci_mem_to_phys(devno, base_address);
+#endif
+
+		if (!pAC->IoBase){
+			printk(KERN_ERR "%s:  Unable to map I/O register, "
+			       "SK 98xx No. %i will be disabled.\n",
+			       dev->name, boards_found);
+			kfree(dev);
+			break;
+		}
+
+		pAC->Index = boards_found;
+		if (SkGeBoardInit(dev, pAC)) {
+			FreeResources(dev);
+			kfree(dev);
+			continue;
+		}
+
+#if 0
+		memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6);
+#else
+		memcpy((caddr_t) &dev->enetaddr,
+			(caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6);
+#endif
+
+#if 0
+		/* First adapter... Create proc and print message */
+		if (!DeviceFound) {
+			DeviceFound = SK_TRUE;
+			SK_MEMCPY(&SK_Root_Dir_entry, BootString,
+				sizeof(SK_Root_Dir_entry) - 1);
+
+			/*Create proc (directory)*/
+			if(!proc_root_initialized) {
+				pSkRootDir = create_proc_entry(SK_Root_Dir_entry,
+					S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net);
+				proc_root_initialized = 1;
+			}
+
+			pSkRootDir->owner = THIS_MODULE;
+		}
+
+
+		/* Create proc file */
+		pProcFile = create_proc_entry(dev->name,
+			S_IFREG | S_IXUSR | S_IWGRP | S_IROTH,
+			pSkRootDir);
+
+
+		pProcFile->read_proc = proc_read;
+		pProcFile->write_proc = NULL;
+		pProcFile->nlink = 1;
+		pProcFile->size = sizeof(dev->name + 1);
+		pProcFile->data = (void *)pProcFile;
+#endif
+
+		pNet->PortNr = 0;
+		pNet->NetNr = 0;
+
+#ifdef SK_ZEROCOPY
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				/* SG and ZEROCOPY - fly baby... */
+				dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+			}
+#endif
+
+		boards_found++;
+
+		/* More then one port found */
+		if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+#if 0
+			if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) {
+				printk(KERN_ERR "Unable to allocate etherdev "
+					"structure!\n");
+				break;
+			}
+#else
+			dev = malloc (sizeof *dev);
+			memset(dev, 0, sizeof(*dev));
+			dev->priv = malloc(sizeof(DEV_NET));
+#endif
+
+			pAC->dev[1] = dev;
+			pNet = dev->priv;
+			pNet->PortNr = 1;
+			pNet->NetNr = 1;
+			pNet->pAC = pAC;
+			pNet->Mtu = 1500;
+			pNet->Up = 0;
+
+#if 0
+			dev->open =		&SkGeOpen;
+			dev->stop =		&SkGeClose;
+			dev->hard_start_xmit =	&SkGeXmit;
+			dev->get_stats =	&SkGeStats;
+			dev->set_multicast_list = &SkGeSetRxMode;
+			dev->set_mac_address =	&SkGeSetMacAddr;
+			dev->do_ioctl =		&SkGeIoctl;
+			dev->change_mtu =	&SkGeChangeMtu;
+			dev->flags &= 		~IFF_RUNNING;
+#endif
+
+#ifdef SK_ZEROCOPY
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				/* SG and ZEROCOPY - fly baby... */
+				dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+			}
+#endif
+
+#if 0
+			pProcFile = create_proc_entry(dev->name,
+				S_IFREG | S_IXUSR | S_IWGRP | S_IROTH,
+				pSkRootDir);
+
+
+			pProcFile->read_proc = proc_read;
+			pProcFile->write_proc = NULL;
+			pProcFile->nlink = 1;
+			pProcFile->size = sizeof(dev->name + 1);
+			pProcFile->data = (void *)pProcFile;
+#endif
+
+#if 0
+			memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
+#else
+			memcpy((caddr_t) &dev->enetaddr,
+			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
+#endif
+
+			printk("%s: %s\n", dev->name, pAC->DeviceStr);
+			printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+
+		}
+
+
+		/* Save the hardware revision */
+		pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+			(pAC->GIni.GIPciHwRev & 0x0F);
+
+		/*
+		 * This is bollocks, but we need to tell the net-init
+		 * code that it shall go for the next device.
+		 */
+#if 0
+#ifndef MODULE
+		dev->base_addr = 0;
+#endif
+#endif
+	}
+
+	/*
+	 * If we're at this point we're going through skge_probe() for
+	 * the first time.  Return success (0) if we've initialized 1
+	 * or more boards. Otherwise, return failure (-ENODEV).
+	 */
+
+	return boards_found;
+} /* skge_probe */
+
+
+/*****************************************************************************
+ *
+ * 	FreeResources - release resources allocated for adapter
+ *
+ * Description:
+ *	This function releases the IRQ, unmaps the IO and
+ *	frees the desriptor ring.
+ *
+ * Returns: N/A
+ *
+ */
+static void FreeResources(struct SK_NET_DEVICE *dev)
+{
+SK_U32 AllocFlag;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
+	if (dev->priv) {
+		pNet = (DEV_NET*) dev->priv;
+		pAC = pNet->pAC;
+		AllocFlag = pAC->AllocFlag;
+#if 0
+		if (AllocFlag & SK_ALLOC_IRQ) {
+			free_irq(dev->irq, dev);
+		}
+		if (pAC->IoBase) {
+			iounmap(pAC->IoBase);
+		}
+#endif
+		if (pAC->pDescrMem) {
+			BoardFreeMem(pAC);
+		}
+	}
+
+} /* FreeResources */
+
+#if 0
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
+MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(Speed_A,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Speed_B,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(AutoNeg_A,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(AutoNeg_B,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(DupCap_A,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(DupCap_B,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(FlowCtrl_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(FlowCtrl_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_A,	    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_B,	    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(PrefPort,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(RlmtMode,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+/* not used, just there because every driver should have them: */
+MODULE_PARM(options,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i");
+MODULE_PARM(debug,      "i");
+#endif
+
+
+#ifdef LINK_SPEED_A
+static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED_A;
+#else
+static char *Speed_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef LINK_SPEED_B
+static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED_B;
+#else
+static char *Speed_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_A
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
+#else
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_A
+static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A;
+#else
+static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_A
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A;
+#else
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_A
+static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A;
+#else
+static char *Role_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_B
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B;
+#else
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_B
+static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B;
+#else
+static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_B
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B;
+#else
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_B
+static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B;
+#else
+static char *Role_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef PREF_PORT
+static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT;
+#else
+static char *PrefPort[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef RLMT_MODE
+static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE;
+#else
+static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#if 0
+static int debug = 0; /* not used */
+static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */
+
+
+/*****************************************************************************
+ *
+ * 	skge_init_module - module initialization function
+ *
+ * Description:
+ *	Very simple, only call skge_probe and return approriate result.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int __init skge_init_module(void)
+{
+	int cards;
+	SkGeRootDev = NULL;
+
+	/* just to avoid warnings ... */
+	debug = 0;
+	options[0] = 0;
+
+	cards = skge_probe();
+	if (cards == 0) {
+		printk("sk98lin: No adapter found.\n");
+	}
+	return cards ? 0 : -ENODEV;
+} /* skge_init_module */
+
+
+/*****************************************************************************
+ *
+ * 	skge_cleanup_module - module unload function
+ *
+ * Description:
+ *	Disable adapter if it is still running, free resources,
+ *	free device struct.
+ *
+ * Returns: N/A
+ */
+static void __exit skge_cleanup_module(void)
+{
+DEV_NET		*pNet;
+SK_AC		*pAC;
+struct SK_NET_DEVICE *next;
+unsigned long Flags;
+SK_EVPARA EvPara;
+
+	while (SkGeRootDev) {
+		pNet = (DEV_NET*) SkGeRootDev->priv;
+		pAC = pNet->pAC;
+		next = pAC->Next;
+
+		netif_stop_queue(SkGeRootDev);
+		SkGeYellowLED(pAC, pAC->IoBase, 0);
+
+		if(pAC->BoardLevel == 2) {
+			/* board is still alive */
+			spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+			EvPara.Para32[0] = 0;
+			EvPara.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			EvPara.Para32[0] = 1;
+			EvPara.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			SkEventDispatcher(pAC, pAC->IoBase);
+			/* disable interrupts */
+			SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+			SkGeDeInit(pAC, pAC->IoBase);
+			spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+			pAC->BoardLevel = 0;
+			/* We do NOT check here, if IRQ was pending, of course*/
+		}
+
+		if(pAC->BoardLevel == 1) {
+			/* board is still alive */
+			SkGeDeInit(pAC, pAC->IoBase);
+			pAC->BoardLevel = 0;
+		}
+
+		if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){
+			unregister_netdev(pAC->dev[1]);
+			kfree(pAC->dev[1]);
+		}
+
+		FreeResources(SkGeRootDev);
+
+		SkGeRootDev->get_stats = NULL;
+		/*
+		 * otherwise unregister_netdev calls get_stats with
+		 * invalid IO ...  :-(
+		 */
+		unregister_netdev(SkGeRootDev);
+		kfree(SkGeRootDev);
+		kfree(pAC);
+		SkGeRootDev = next;
+	}
+
+	/* clear proc-dir */
+	remove_proc_entry(pSkRootDir->name, proc_net);
+
+} /* skge_cleanup_module */
+
+module_init(skge_init_module);
+module_exit(skge_cleanup_module);
+#endif
+
+
+/*****************************************************************************
+ *
+ * 	SkGeBoardInit - do level 0 and 1 initialization
+ *
+ * Description:
+ *	This function prepares the board hardware for running. The desriptor
+ *	ring is set up, the IRQ is allocated and the configuration settings
+ *	are examined.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+{
+short	i;
+unsigned long Flags;
+char	*DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
+char	*VerStr	= VER_STRING;
+#if 0
+int	Ret;			/* return code of request_irq */
+#endif
+SK_BOOL	DualNet;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
+	for (i=0; i<SK_MAX_MACS; i++) {
+		pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0];
+		pAC->TxPort[i][0].PortIndex = i;
+		pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i];
+		pAC->RxPort[i].PortIndex = i;
+	}
+
+	/* Initialize the mutexes */
+	for (i=0; i<SK_MAX_MACS; i++) {
+		spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
+		spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
+	}
+	spin_lock_init(&pAC->SlowPathLock);
+
+	/* level 0 init common modules here */
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	/* Does a RESET on board ...*/
+	if (SkGeInit(pAC, pAC->IoBase, 0) != 0) {
+		printk("HWInit (0) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return(-EAGAIN);
+	}
+	SkI2cInit(  pAC, pAC->IoBase, 0);
+	SkEventInit(pAC, pAC->IoBase, 0);
+	SkPnmiInit( pAC, pAC->IoBase, 0);
+	SkAddrInit( pAC, pAC->IoBase, 0);
+	SkRlmtInit( pAC, pAC->IoBase, 0);
+	SkTimerInit(pAC, pAC->IoBase, 0);
+
+	pAC->BoardLevel = 0;
+	pAC->RxBufSize = ETH_BUF_SIZE;
+
+	SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString);
+	SK_PNMI_SET_DRIVER_VER(pAC, VerStr);
+
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	/* level 1 init common modules here (HW init) */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
+		printk("HWInit (1) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return(-EAGAIN);
+	}
+	SkI2cInit(  pAC, pAC->IoBase, 1);
+	SkEventInit(pAC, pAC->IoBase, 1);
+	SkPnmiInit( pAC, pAC->IoBase, 1);
+	SkAddrInit( pAC, pAC->IoBase, 1);
+	SkRlmtInit( pAC, pAC->IoBase, 1);
+	SkTimerInit(pAC, pAC->IoBase, 1);
+
+	GetConfiguration(pAC);
+	if (pAC->RlmtNets == 2) {
+		pAC->GIni.GIPortUsage = SK_MUL_LINK;
+	}
+
+	pAC->BoardLevel = 1;
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+#if 0
+	if (pAC->GIni.GIMacsFound == 2) {
+		 Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, pAC->Name, dev);
+	} else if (pAC->GIni.GIMacsFound == 1) {
+		Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
+			pAC->Name, dev);
+	} else {
+		printk(KERN_WARNING "%s: Illegal number of ports: %d\n",
+		       dev->name, pAC->GIni.GIMacsFound);
+		return -EAGAIN;
+	}
+
+	if (Ret) {
+		printk(KERN_WARNING "%s: Requested IRQ %d is busy.\n",
+		       dev->name, dev->irq);
+		return -EAGAIN;
+	}
+#endif
+	pAC->AllocFlag |= SK_ALLOC_IRQ;
+
+	/* Alloc memory for this board (Mem for RxD/TxD) : */
+	if(!BoardAllocMem(pAC)) {
+		printk("No memory for descriptor rings.\n");
+		return(-EAGAIN);
+	}
+
+	SkCsSetReceiveFlags(pAC,
+		SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP,
+		&pAC->CsOfs1, &pAC->CsOfs2, 0);
+	pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;
+
+	BoardInitMem(pAC);
+#if 0
+	SetQueueSizes(pAC);
+#else
+	/* tschilling: New common function with minimum size check. */
+	DualNet = SK_FALSE;
+	if (pAC->RlmtNets == 2) {
+		DualNet = SK_TRUE;
+	}
+
+	if (SkGeInitAssignRamToQueues(
+		pAC,
+		pAC->ActivePort,
+		DualNet)) {
+		BoardFreeMem(pAC);
+		printk("SkGeInitAssignRamToQueues failed.\n");
+		return(-EAGAIN);
+	}
+#endif
+
+	/* Print adapter specific string from vpd */
+	ProductStr(pAC);
+#ifdef SK98_INFO
+	printk("%s: %s\n", dev->name, pAC->DeviceStr);
+
+	/* Print configuration settings */
+	printk("      PrefPort:%c  RlmtMode:%s\n",
+		'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+		(pAC->RlmtMode==0)  ? "Check Link State" :
+		((pAC->RlmtMode==1) ? "Check Link State" :
+		((pAC->RlmtMode==3) ? "Check Local Port" :
+		((pAC->RlmtMode==7) ? "Check Segmentation" :
+		((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+#endif
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+	/*
+	 * Register the device here
+	 */
+	pAC->Next = SkGeRootDev;
+	SkGeRootDev = dev;
+
+	return (0);
+} /* SkGeBoardInit */
+
+
+/*****************************************************************************
+ *
+ * 	BoardAllocMem - allocate the memory for the descriptor rings
+ *
+ * Description:
+ *	This function allocates the memory for all descriptor rings.
+ *	Each ring is aligned for the desriptor alignment and no ring
+ *	has a 4 GByte boundary in it (because the upper 32 bit must
+ *	be constant for all descriptiors in one rings).
+ *
+ * Returns:
+ *	SK_TRUE, if all memory could be allocated
+ *	SK_FALSE, if not
+ */
+static SK_BOOL BoardAllocMem(
+SK_AC	*pAC)
+{
+caddr_t		pDescrMem;	/* pointer to descriptor memory area */
+size_t		AllocLength;	/* length of complete descriptor area */
+int		i;		/* loop counter */
+unsigned long	BusAddr;
+
+
+	/* rings plus one for alignment (do not cross 4 GB boundary) */
+	/* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */
+#if (BITS_PER_LONG == 32)
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+		+ RX_RING_SIZE + 8;
+#endif
+
+	pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength,
+					 &pAC->pDescrMemDMA);
+
+	if (pDescrMem == NULL) {
+		return (SK_FALSE);
+	}
+	pAC->pDescrMem = pDescrMem;
+	BusAddr = (unsigned long) pAC->pDescrMemDMA;
+
+	/* Descriptors need 8 byte alignment, and this is ensured
+	 * by pci_alloc_consistent.
+	 */
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("TX%d/A: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			BusAddr));
+		pAC->TxPort[i][0].pTxDescrRing = pDescrMem;
+		pAC->TxPort[i][0].VTxDescrRing = BusAddr;
+		pDescrMem += TX_RING_SIZE;
+		BusAddr += TX_RING_SIZE;
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("RX%d: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			(unsigned long)BusAddr));
+		pAC->RxPort[i].pRxDescrRing = pDescrMem;
+		pAC->RxPort[i].VRxDescrRing = BusAddr;
+		pDescrMem += RX_RING_SIZE;
+		BusAddr += RX_RING_SIZE;
+	} /* for */
+
+	return (SK_TRUE);
+} /* BoardAllocMem */
+
+
+/****************************************************************************
+ *
+ *	BoardFreeMem - reverse of BoardAllocMem
+ *
+ * Description:
+ *	Free all memory allocated in BoardAllocMem: adapter context,
+ *	descriptor rings, locks.
+ *
+ * Returns:	N/A
+ */
+static void BoardFreeMem(
+SK_AC		*pAC)
+{
+size_t		AllocLength;	/* length of complete descriptor area */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardFreeMem\n"));
+#if (BITS_PER_LONG == 32)
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+		+ RX_RING_SIZE + 8;
+#endif
+
+	pci_free_consistent(pAC->PciDev, AllocLength,
+			    pAC->pDescrMem, pAC->pDescrMemDMA);
+	pAC->pDescrMem = NULL;
+} /* BoardFreeMem */
+
+
+/*****************************************************************************
+ *
+ * 	BoardInitMem - initiate the descriptor rings
+ *
+ * Description:
+ *	This function sets the descriptor rings up in memory.
+ *	The adapter is initialized with the descriptor start addresses.
+ *
+ * Returns:	N/A
+ */
+static void BoardInitMem(
+SK_AC	*pAC)	/* pointer to adapter context */
+{
+int	i;		/* loop counter */
+int	RxDescrSize;	/* the size of a rx descriptor rounded up to alignment*/
+int	TxDescrSize;	/* the size of a tx descriptor rounded up to alignment*/
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardInitMem\n"));
+
+	RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize;
+	TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize;
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SetupRing(
+			pAC,
+			pAC->TxPort[i][0].pTxDescrRing,
+			pAC->TxPort[i][0].VTxDescrRing,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingHead,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingTail,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingPrev,
+			&pAC->TxPort[i][0].TxdRingFree,
+			SK_TRUE);
+		SetupRing(
+			pAC,
+			pAC->RxPort[i].pRxDescrRing,
+			pAC->RxPort[i].VRxDescrRing,
+			&pAC->RxPort[i].pRxdRingHead,
+			&pAC->RxPort[i].pRxdRingTail,
+			&pAC->RxPort[i].pRxdRingPrev,
+			&pAC->RxPort[i].RxdRingFree,
+			SK_FALSE);
+	}
+} /* BoardInitMem */
+
+
+/*****************************************************************************
+ *
+ * 	SetupRing - create one descriptor ring
+ *
+ * Description:
+ *	This function creates one descriptor ring in the given memory area.
+ *	The head, tail and number of free descriptors in the ring are set.
+ *
+ * Returns:
+ *	none
+ */
+static void SetupRing(
+SK_AC		*pAC,
+void		*pMemArea,	/* a pointer to the memory area for the ring */
+uintptr_t	VMemArea,	/* the virtual bus address of the memory area */
+RXD		**ppRingHead,	/* address where the head should be written */
+RXD		**ppRingTail,	/* address where the tail should be written */
+RXD		**ppRingPrev,	/* address where the tail should be written */
+int		*pRingFree,	/* address where the # of free descr. goes */
+SK_BOOL		IsTx)		/* flag: is this a tx ring */
+{
+int	i;		/* loop counter */
+int	DescrSize;	/* the size of a descriptor rounded up to alignment*/
+int	DescrNum;	/* number of descriptors per ring */
+RXD	*pDescr;	/* pointer to a descriptor (receive or transmit) */
+RXD	*pNextDescr;	/* pointer to the next descriptor */
+RXD	*pPrevDescr;	/* pointer to the previous descriptor */
+uintptr_t VNextDescr;	/* the virtual bus address of the next descriptor */
+
+	if (IsTx == SK_TRUE) {
+		DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = TX_RING_SIZE / DescrSize;
+	} else {
+		DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = RX_RING_SIZE / DescrSize;
+	}
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+		("Descriptor size: %d   Descriptor Number: %d\n",
+		DescrSize,DescrNum));
+
+	pDescr = (RXD*) pMemArea;
+	pPrevDescr = NULL;
+	pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+	VNextDescr = VMemArea + DescrSize;
+	for(i=0; i<DescrNum; i++) {
+		/* set the pointers right */
+		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
+		pDescr->pNextRxd = pNextDescr;
+		pDescr->TcpSumStarts = pAC->CsOfs;
+
+		/* advance one step */
+		pPrevDescr = pDescr;
+		pDescr = pNextDescr;
+		pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+		VNextDescr += DescrSize;
+	}
+	pPrevDescr->pNextRxd = (RXD*) pMemArea;
+	pPrevDescr->VNextRxd = VMemArea;
+	pDescr = (RXD*) pMemArea;
+	*ppRingHead = (RXD*) pMemArea;
+	*ppRingTail = *ppRingHead;
+	*ppRingPrev = pPrevDescr;
+	*pRingFree = DescrNum;
+} /* SetupRing */
+
+
+/*****************************************************************************
+ *
+ * 	PortReInitBmu - re-initiate the descriptor rings for one port
+ *
+ * Description:
+ *	This function reinitializes the descriptor rings of one port
+ *	in memory. The port must be stopped before.
+ *	The HW is initialized with the descriptor start addresses.
+ *
+ * Returns:
+ *	none
+ */
+static void PortReInitBmu(
+SK_AC	*pAC,		/* pointer to adapter context */
+int	PortIndex)	/* index of the port for which to re-init */
+{
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("PortReInitBmu "));
+
+	/* set address of first descriptor of ring in BMU */
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+
+		TX_Q_CUR_DESCR_LOW,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) &
+		0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+
+		TX_Q_DESCR_HIGH,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CUR_DESCR_LOW,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_DESCR_HIGH,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) >> 32));
+} /* PortReInitBmu */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsr - handle adapter interrupts
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *
+ * Returns: N/A
+ *
+ */
+#if 0
+static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
+#else
+void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
+#endif
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return;
+	}
+
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IRQ_EOF_RX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 0);
+		}
+		if (IntSrc & IRQ_EOF_RX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX2 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 1);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+		if (IntSrc & IRQ_EOF_AS_TX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IRQ_EOF_SY_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+		if (IntSrc & IRQ_EOF_SY_TX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
+		}
+#endif
+#endif
+
+		/* do all IO at once */
+		if (IntSrc & IRQ_EOF_RX1)
+			ClearAndStartRx(pAC, 0);
+		if (IntSrc & IRQ_EOF_RX2)
+			ClearAndStartRx(pAC, 1);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+		if (IntSrc & IRQ_EOF_AS_TX2)
+			ClearTxIrq(pAC, 1, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ DP-Cards => %x\n", IntSrc));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 */
+
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+	ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+
+	if (pAC->CheckQueue) {
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+
+	return;
+} /* SkGeIsr */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsrOnePort - handle adapter interrupts for single port adapter
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *	This is the same as above, but handles only one port.
+ *
+ * Returns: N/A
+ *
+ */
+#if 0
+static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
+#else
+void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
+#endif
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return;
+	}
+
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IRQ_EOF_RX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 0);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IRQ_EOF_SY_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+#endif
+#endif
+
+		/* do all IO at once */
+		if (IntSrc & IRQ_EOF_RX1)
+			ClearAndStartRx(pAC, 0);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ SP-Cards => %x\n", IntSrc));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 */
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+
+	return;
+} /* SkGeIsrOnePort */
+
+
+/****************************************************************************
+ *
+ *	SkGeOpen - handle start of initialized adapter
+ *
+ * Description:
+ *	This function starts the initialized adapter.
+ *	The board level variable is set and the adapter is
+ *	brought to full functionality.
+ *	The device flags are set for operation.
+ *	Do all necessary level 2 initialization, enable interrupts and
+ *	give start command to RLMT.
+ *
+ * Returns:
+ *	0 on success
+ *	!= 0 on error
+ */
+#if 0
+static int SkGeOpen(
+#else
+int SkGeOpen(
+#endif
+struct SK_NET_DEVICE	*dev)
+{
+	DEV_NET			*pNet;
+	SK_AC			*pAC;
+	unsigned long	Flags;		/* for spin lock */
+	int				i;
+	SK_EVPARA		EvPara;		/* an event parameter union */
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
+
+	if (pAC->BoardLevel == 0) {
+		/* level 1 init common modules here */
+		if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
+			printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name);
+			return (-1);
+		}
+		SkI2cInit	(pAC, pAC->IoBase, 1);
+		SkEventInit	(pAC, pAC->IoBase, 1);
+		SkPnmiInit	(pAC, pAC->IoBase, 1);
+		SkAddrInit	(pAC, pAC->IoBase, 1);
+		SkRlmtInit	(pAC, pAC->IoBase, 1);
+		SkTimerInit	(pAC, pAC->IoBase, 1);
+		pAC->BoardLevel = 1;
+	}
+
+	if (pAC->BoardLevel != 2) {
+		/* tschilling: Level 2 init modules here, check return value. */
+		if (SkGeInit(pAC, pAC->IoBase, 2) != 0) {
+			printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name);
+			return (-1);
+		}
+		SkI2cInit	(pAC, pAC->IoBase, 2);
+		SkEventInit	(pAC, pAC->IoBase, 2);
+		SkPnmiInit	(pAC, pAC->IoBase, 2);
+		SkAddrInit	(pAC, pAC->IoBase, 2);
+		SkRlmtInit	(pAC, pAC->IoBase, 2);
+		SkTimerInit	(pAC, pAC->IoBase, 2);
+		pAC->BoardLevel = 2;
+	}
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		/* Enable transmit descriptor polling. */
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	}
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+#ifdef USE_INT_MOD
+/* moderate only TX complete interrupts (these are not time critical) */
+#define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2)
+	{
+		unsigned long ModBase;
+		ModBase = 53125000 / INTS_PER_SEC;
+		SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+		SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK);
+		SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+	}
+#endif
+
+	/* enable Interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) {
+		EvPara.Para32[0] = pAC->RlmtNets;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+			EvPara);
+		EvPara.Para32[0] = pAC->RlmtMode;
+		EvPara.Para32[1] = 0;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
+			EvPara);
+	}
+
+	EvPara.Para32[0] = pNet->NetNr;
+	EvPara.Para32[1] = -1;
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	pAC->MaxPorts++;
+	pNet->Up = 1;
+
+	MOD_INC_USE_COUNT;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen suceeded\n"));
+
+	return (0);
+} /* SkGeOpen */
+
+
+/****************************************************************************
+ *
+ *	SkGeClose - Stop initialized adapter
+ *
+ * Description:
+ *	Close initialized adapter.
+ *
+ * Returns:
+ *	0 - on success
+ *	error code - on error
+ */
+#if 0
+static int SkGeClose(
+#else
+int SkGeClose(
+#endif
+struct SK_NET_DEVICE	*dev)
+{
+	DEV_NET			*pNet;
+	SK_AC			*pAC;
+
+	unsigned long	Flags;		/* for spin lock */
+	int				i;
+	int				PortIdx;
+	SK_EVPARA		EvPara;
+
+	netif_stop_queue(dev);
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
+
+	/*
+	 * Clear multicast table, promiscuous mode ....
+	 */
+	SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+	SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+		SK_PROM_MODE_NONE);
+
+	if (pAC->MaxPorts == 1) {
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* stop the hardware */
+		SkGeDeInit(pAC, pAC->IoBase);
+		pAC->BoardLevel = 0;
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	} else {
+
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+		/* Stop port */
+		spin_lock_irqsave(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+		SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr,
+			SK_STOP_ALL, SK_HARD_RST);
+		spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+	}
+
+	if (pAC->RlmtNets == 1) {
+		/* clear all descriptor rings */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+			ClearRxRing(pAC, &pAC->RxPort[i]);
+			ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+		}
+	} else {
+		/* clear port descriptor rings */
+		ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE);
+		ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
+		ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
+	}
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: done "));
+
+	pAC->MaxPorts--;
+	pNet->Up = 0;
+	MOD_DEC_USE_COUNT;
+
+	return (0);
+} /* SkGeClose */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeXmit - Linux frame transmit function
+ *
+ * Description:
+ *	The system calls this function to send frames onto the wire.
+ *	It puts the frame in the tx descriptor ring. If the ring is
+ *	full then, the 'tbusy' flag is set.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ * WARNING: returning 1 in 'tbusy' case caused system crashes (double
+ *	allocated skb's) !!!
+ */
+#if 0
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
+#else
+int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
+#endif
+{
+DEV_NET		*pNet;
+SK_AC		*pAC;
+int			Rc;	/* return code of XmitFrame */
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+#if 0
+	if ((!skb_shinfo(skb)->nr_frags) ||
+#else
+	if (1 ||
+#endif
+		(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) {
+		/* Don't activate scatter-gather and hardware checksum */
+
+		if (pAC->RlmtNets == 2)
+			Rc = XmitFrame(
+				pAC,
+				&pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+				skb);
+		else
+			Rc = XmitFrame(
+				pAC,
+				&pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+				skb);
+	} else {
+#if 0
+		/* scatter-gather and hardware TCP checksumming anabled*/
+		if (pAC->RlmtNets == 2)
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+				skb);
+		else
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+				skb);
+#endif
+	}
+
+	/* Transmitter out of resources? */
+	if (Rc <= 0) {
+		netif_stop_queue(dev);
+	}
+
+	/* If not taken, give buffer ownership back to the
+	 * queueing layer.
+	 */
+	if (Rc < 0)
+		return (1);
+
+#if 0
+	dev->trans_start = jiffies;
+#endif
+	return (0);
+} /* SkGeXmit */
+
+
+/*****************************************************************************
+ *
+ * 	XmitFrame - fill one socket buffer into the transmit ring
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *	Linux skb's consist of only one continuous buffer.
+ *	The first step locks the ring. It is held locked
+ *	all time to avoid problems with SWITCH_../PORT_RESET.
+ *	Then the descriptoris allocated.
+ *	The second part is linking the buffer to the descriptor.
+ *	At the very last, the Control field of the descriptor
+ *	is made valid for the BMU and a start TX command is given
+ *	if necessary.
+ *
+ * Returns:
+ *	> 0 - on succes: the number of bytes in the message
+ *	= 0 - on resource shortage: this frame sent or dropped, now
+ *		the ring is full ( -> set tbusy)
+ *	< 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrame(
+SK_AC 		*pAC,		/* pointer to adapter context */
+TX_PORT		*pTxPort,	/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message */
+{
+TXD		*pTxd;		/* the rxd to fill */
+unsigned long	Flags;
+SK_U64		PhysAddr;
+int		BytesSend;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+		("X"));
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
+	if (pTxPort->TxdRingFree == 0) {
+		/* no enough free descriptors in ring at the moment */
+		FreeTxDescriptors(pAC, pTxPort);
+		if (pTxPort->TxdRingFree == 0) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrame failed\n"));
+			/* this message can not be sent now */
+			/* Because tbusy seems to be set, the message should not be freed here */
+			/* It will be used by the scheduler of the ethernet handler */
+			return (-1);
+		}
+	}
+	/* advance head counter behind descriptor needed for this frame */
+	pTxd = pTxPort->pTxdRingHead;
+	pTxPort->pTxdRingHead = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+	/* the needed descriptor is reserved now */
+
+	/*
+	 * everything allocated ok, so add buffer to descriptor
+	 */
+
+#ifdef SK_DUMP_TX
+	DumpMsg(pMessage, "XmitFrame");
+#endif
+
+	/* set up descriptor and CONTROL dword */
+#if 0
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+		virt_to_page(pMessage->data),
+		((unsigned long) pMessage->data &
+		~PAGE_MASK),
+		pMessage->len,
+		PCI_DMA_TODEVICE);
+#else
+	PhysAddr = (SK_U64) pci_phys_to_mem(pAC->PciDev, (u32) pMessage->data);
+#endif
+	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pTxd->pMBuf = pMessage;
+	pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF |
+		TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |
+#ifdef USE_TX_COMPLETE
+		TX_CTRL_EOF | TX_CTRL_EOF_IRQ | pMessage->len;
+#else
+		TX_CTRL_EOF | pMessage->len;
+#endif
+
+	if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) {
+		/* previous descriptor already done, so give tx start cmd */
+		/* StartTx(pAC, pTxPort->HwAddr); */
+		SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START);
+	}
+	pTxPort->pTxdRingPrev = pTxd;
+
+
+	BytesSend = pMessage->len;
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+	/* after releasing the lock, the skb may be immidiately freed */
+	if (pTxPort->TxdRingFree != 0)
+		return (BytesSend);
+	else
+		return (0);
+
+} /* XmitFrame */
+
+/*****************************************************************************
+ *
+ * 	XmitFrameSG - fill one socket buffer into the transmit ring
+ *                (use SG and TCP/UDP hardware checksumming)
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *
+ * Returns:
+ *	> 0 - on succes: the number of bytes in the message
+ *	= 0 - on resource shortage: this frame sent or dropped, now
+ *		the ring is full ( -> set tbusy)
+ *	< 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+#if 0
+static int XmitFrameSG(
+SK_AC 		*pAC,			/* pointer to adapter context */
+TX_PORT		*pTxPort,		/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message */
+{
+
+	int 		i;
+	int			BytesSend;
+	int			hlength;
+	int			protocol;
+	skb_frag_t		*sk_frag;
+	TXD			*pTxd;
+	TXD			*pTxdFst;
+	TXD			*pTxdLst;
+	SK_U64		PhysAddr;
+	unsigned long	Flags;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
+	if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) {
+		FreeTxDescriptors(pAC, pTxPort);
+		if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrameSG failed - Ring full\n"));
+				/* this message can not be sent now */
+			return(-1);
+		}
+	}
+
+
+	pTxd = pTxPort->pTxdRingHead;
+	pTxdFst = pTxd;
+	pTxdLst = pTxd;
+	BytesSend = 0;
+	protocol = 0;
+
+	/* map first fragment (header) */
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+			virt_to_page(pMessage->data),
+			((unsigned long) pMessage->data & ~PAGE_MASK),
+			skb_headlen(pMessage),
+			PCI_DMA_TODEVICE);
+
+	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+
+	/* HW checksum? */
+	if (pMessage->ip_summed == CHECKSUM_HW) {
+		pTxd->TBControl = TX_CTRL_STF |
+				  TX_CTRL_ST_FWD |
+				  skb_headlen(pMessage);
+
+		/* We have to use the opcode for tcp here because the opcode for
+		udp is not working in the hardware yet (revision 2.0)*/
+		protocol = ((SK_U8)pMessage->data[23] & 0xf);
+		if ((protocol == 17) && (pAC->GIni.GIChipRev != 0))
+			pTxd->TBControl |=  BMU_UDP_CHECK;
+		else
+			pTxd->TBControl |= BMU_TCP_CHECK ;
+
+		hlength = ((SK_U8)pMessage->data[14] & 0xf) * 4;
+		pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */
+		pTxd->TcpSumSt = 14+hlength+16;
+		pTxd->TcpSumWr = 14+hlength;
+
+	} else {
+		pTxd->TBControl = TX_CTRL_CHECK_DEFAULT |
+				  TX_CTRL_SOFTWARE |
+				  TX_CTRL_STF |
+				  skb_headlen(pMessage);
+	}
+
+	pTxd = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+	BytesSend += skb_headlen(pMessage);
+
+
+	/* Map SG fragments */
+	for (i = 0; i < skb_shinfo(pMessage)->nr_frags; i++) {
+		sk_frag = &skb_shinfo(pMessage)->frags[i];
+
+		/* we already have the proper value in entry */
+		PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+						 sk_frag->page,
+						 sk_frag->page_offset,
+						 sk_frag->size,
+						 PCI_DMA_TODEVICE);
+
+		pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+		pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+		pTxd->pMBuf = pMessage;
+
+		/* HW checksum */
+		if (pMessage->ip_summed == CHECKSUM_HW) {
+			pTxd->TBControl = TX_CTRL_OWN_BMU |
+					  TX_CTRL_SOFTWARE |
+					  TX_CTRL_ST_FWD;
+
+			/* We have to use the opcode for tcp here because the opcode for
+			udp is not working in the hardware yet (revision 2.0)*/
+			if ((protocol == 17) && (pAC->GIni.GIChipRev != 0))
+				pTxd->TBControl |= BMU_UDP_CHECK ;
+			else
+				pTxd->TBControl |= BMU_TCP_CHECK ;
+
+		} else {
+			pTxd->TBControl = TX_CTRL_CHECK_DEFAULT |
+					  TX_CTRL_SOFTWARE |
+					  TX_CTRL_OWN_BMU;
+		}
+
+		/* Last fragment  */
+		if( (i+1) == skb_shinfo(pMessage)->nr_frags )  {
+#ifdef USE_TX_COMPLETE
+			pTxd->TBControl |= TX_CTRL_EOF |
+					   TX_CTRL_EOF_IRQ |
+					   sk_frag->size;
+#else
+			pTxd->TBControl |= TX_CTRL_EOF |
+					   sk_frag->size;
+#endif
+			pTxdFst->TBControl |= TX_CTRL_OWN_BMU |
+					      TX_CTRL_SOFTWARE;
+
+		} else {
+			pTxd->TBControl |= sk_frag->size;
+		}
+		pTxdLst = pTxd;
+		pTxd = pTxd->pNextTxd;
+		pTxPort->TxdRingFree--;
+		BytesSend += sk_frag->size;
+	}
+
+	if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) {
+		/* previous descriptor already done, so give tx start cmd */
+		/* StartTx(pAC, pTxPort->HwAddr); */
+		SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START);
+	}
+
+	pTxPort->pTxdRingPrev = pTxdLst;
+	pTxPort->pTxdRingHead = pTxd;
+
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+
+	if (pTxPort->TxdRingFree > 0)
+		return (BytesSend);
+	else
+		return (0);
+}
+#endif
+
+
+void dump_frag( SK_U8 *data, int length)
+{
+	int i;
+
+	printk("Length: %d\n", length);
+	for( i=0; i < length; i++ ) {
+		printk(" %02x", (SK_U8)*(data + i) );
+		if( !((i+1) % 20) )
+		  printk("\n");
+	}
+	printk("\n\n");
+
+}
+
+
+/*****************************************************************************
+ *
+ * 	FreeTxDescriptors - release descriptors from the descriptor ring
+ *
+ * Description:
+ *	This function releases descriptors from a transmit ring if they
+ *	have been sent by the BMU.
+ *	If a descriptors is sent, it can be freed and the message can
+ *	be freed, too.
+ *	The SOFTWARE controllable bit is used to prevent running around a
+ *	completely free ring for ever. If this bit is no set in the
+ *	frame (by XmitFrame), this frame has never been sent or is
+ *	already freed.
+ *	The Tx descriptor ring lock must be held while calling this function !!!
+ *
+ * Returns:
+ *	none
+ */
+static void FreeTxDescriptors(
+SK_AC	*pAC,		/* pointer to the adapter context */
+TX_PORT	*pTxPort)	/* pointer to destination port structure */
+{
+TXD	*pTxd;		/* pointer to the checked descriptor */
+TXD	*pNewTail;	/* pointer to 'end' of the ring */
+SK_U32	Control;	/* TBControl field of descriptor */
+SK_U64	PhysAddr;	/* address of DMA mapping */
+
+	pNewTail = pTxPort->pTxdRingTail;
+	pTxd = pNewTail;
+	/*
+	 * loop forever; exits if TX_CTRL_SOFTWARE bit not set in start frame
+	 * or TX_CTRL_OWN_BMU bit set in any frame
+	 */
+	while (1) {
+		Control = pTxd->TBControl;
+		if ((Control & TX_CTRL_SOFTWARE) == 0) {
+			/*
+			 * software controllable bit is set in first
+			 * fragment when given to BMU. Not set means that
+			 * this fragment was never sent or is already
+			 * freed ( -> ring completely free now).
+			 */
+			pTxPort->pTxdRingTail = pTxd;
+			netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+			return;
+		}
+		if (Control & TX_CTRL_OWN_BMU) {
+			pTxPort->pTxdRingTail = pTxd;
+			if (pTxPort->TxdRingFree > 0) {
+				netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+			}
+			return;
+		}
+
+		/* release the DMA mapping */
+		PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
+		PhysAddr |= (SK_U64) pTxd->VDataLow;
+		pci_unmap_page(pAC->PciDev, PhysAddr,
+				 pTxd->pMBuf->len,
+				 PCI_DMA_TODEVICE);
+
+		if (Control & TX_CTRL_EOF)
+			DEV_KFREE_SKB_ANY(pTxd->pMBuf);	/* free message */
+
+		pTxPort->TxdRingFree++;
+		pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
+		pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
+	} /* while(forever) */
+} /* FreeTxDescriptors */
+
+/*****************************************************************************
+ *
+ * 	FillRxRing - fill the receive ring with valid descriptors
+ *
+ * Description:
+ *	This function fills the receive ring descriptors with data
+ *	segments and makes them valid for the BMU.
+ *	The active ring is filled completely, if possible.
+ *	The non-active ring is filled only partial to save memory.
+ *
+ * Description of rx ring structure:
+ *	head - points to the descriptor which will be used next by the BMU
+ *	tail - points to the next descriptor to give to the BMU
+ *
+ * Returns:	N/A
+ */
+static void FillRxRing(
+SK_AC		*pAC,		/* pointer to the adapter context */
+RX_PORT		*pRxPort)	/* ptr to port struct for which the ring
+				   should be filled */
+{
+unsigned long	Flags;
+
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
+		if(!FillRxDescriptor(pAC, pRxPort))
+			break;
+	}
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* FillRxRing */
+
+
+/*****************************************************************************
+ *
+ * 	FillRxDescriptor - fill one buffer into the receive ring
+ *
+ * Description:
+ *	The function allocates a new receive buffer and
+ *	puts it into the next descriptor.
+ *
+ * Returns:
+ *	SK_TRUE - a buffer was added to the ring
+ *	SK_FALSE - a buffer could not be added
+ */
+static SK_BOOL FillRxDescriptor(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort)	/* ptr to port struct of ring to fill */
+{
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+SK_U64		PhysAddr;	/* physical address of a rx buffer */
+
+	pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+			SK_DBGCAT_DRV_ENTRY,
+			("%s: Allocation of rx buffer failed !\n",
+			pAC->dev[pRxPort->PortIndex]->name));
+		SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex);
+		return(SK_FALSE);
+	}
+	skb_reserve(pMsgBlock, 2); /* to align IP frames */
+	/* skb allocated ok, so add buffer */
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+#if 0
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+		virt_to_page(pMsgBlock->data),
+		((unsigned long) pMsgBlock->data &
+		~PAGE_MASK),
+		pAC->RxBufSize - 2,
+		PCI_DMA_FROMDEVICE);
+#else
+	PhysAddr = (SK_U64) pci_phys_to_mem(pAC->PciDev, (u32)pMsgBlock->data);
+#endif
+	pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pRxd->pMBuf = pMsgBlock;
+	pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF |
+		RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length;
+	return (SK_TRUE);
+
+} /* FillRxDescriptor */
+
+
+/*****************************************************************************
+ *
+ * 	ReQueueRxBuffer - fill one buffer back into the receive ring
+ *
+ * Description:
+ *	Fill a given buffer back into the rx ring. The buffer
+ *	has been previously allocated and aligned, and its phys.
+ *	address calculated, so this is no more necessary.
+ *
+ * Returns: N/A
+ */
+static void ReQueueRxBuffer(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort,	/* ptr to port struct of ring to fill */
+struct sk_buff	*pMsg,		/* pointer to the buffer */
+SK_U32		PhysHigh,	/* phys address high dword */
+SK_U32		PhysLow)	/* phys address low dword */
+{
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+	pRxd->VDataLow = PhysLow;
+	pRxd->VDataHigh = PhysHigh;
+	pRxd->pMBuf = pMsg;
+	pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF |
+		RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length;
+	return;
+} /* ReQueueRxBuffer */
+
+
+/*****************************************************************************
+ *
+ * 	ReceiveIrq - handle a receive IRQ
+ *
+ * Description:
+ *	This function is called when a receive IRQ is set.
+ *	It walks the receive descriptor ring and sends up all
+ *	frames that are complete.
+ *
+ * Returns:	N/A
+ */
+#if 0
+static void ReceiveIrq(
+#else
+void ReceiveIrq(
+#endif
+	SK_AC		*pAC,			/* pointer to adapter context */
+	RX_PORT		*pRxPort,		/* pointer to receive port struct */
+	SK_BOOL		SlowPathLock)	/* indicates if SlowPathLock is needed */
+{
+RXD				*pRxd;			/* pointer to receive descriptors */
+SK_U32			Control;		/* control field of descriptor */
+struct sk_buff	*pMsg;			/* pointer to message holding frame */
+struct sk_buff	*pNewMsg;		/* pointer to a new message for copying frame */
+int				FrameLength;	/* total length of received frame */
+SK_MBUF			*pRlmtMbuf;		/* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA		EvPara;			/* an event parameter union */
+unsigned long	Flags;			/* for spin lock */
+int				PortIndex = pRxPort->PortIndex;
+unsigned int	Offset;
+unsigned int	NumBytes;
+unsigned int	ForRlmt;
+SK_BOOL			IsBc;
+SK_BOOL			IsMc;
+SK_BOOL  IsBadFrame; 			/* Bad frame */
+
+SK_U32			FrameStat;
+unsigned short	Csum1;
+unsigned short	Csum2;
+unsigned short	Type;
+#if 0
+int				Result;
+#endif
+SK_U64			PhysAddr;
+
+rx_start:
+	/* do forever; exit if RX_CTRL_OWN_BMU found */
+	for ( pRxd = pRxPort->pRxdRingHead ;
+		  pRxPort->RxdRingFree < pAC->RxDescrPerRing ;
+		  pRxd = pRxd->pNextRxd,
+		  pRxPort->pRxdRingHead = pRxd,
+		  pRxPort->RxdRingFree ++) {
+
+		/*
+		 * For a better understanding of this loop
+		 * Go through every descriptor beginning at the head
+		 * Please note: the ring might be completely received so the OWN bit
+		 * set is not a good crirteria to leave that loop.
+		 * Therefore the RingFree counter is used.
+		 * On entry of this loop pRxd is a pointer to the Rxd that needs
+		 * to be checked next.
+		 */
+
+		Control = pRxd->RBControl;
+
+		/* check if this descriptor is ready */
+		if ((Control & RX_CTRL_OWN_BMU) != 0) {
+			/* this descriptor is not yet ready */
+			/* This is the usual end of the loop */
+			/* We don't need to start the ring again */
+			FillRxRing(pAC, pRxPort);
+			return;
+		}
+
+		/* get length of frame and check it */
+		FrameLength = Control & RX_CTRL_LEN_MASK;
+		if (FrameLength > pAC->RxBufSize) {
+			goto rx_failed;
+		}
+
+		/* check for STF and EOF */
+		if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) !=
+			(RX_CTRL_STF | RX_CTRL_EOF)) {
+			goto rx_failed;
+		}
+
+		/* here we have a complete frame in the ring */
+		pMsg = pRxd->pMBuf;
+
+		FrameStat = pRxd->FrameStat;
+
+		/* check for frame length mismatch */
+#define XMR_FS_LEN_SHIFT        18
+#define GMR_FS_LEN_SHIFT        16
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+		else {
+			if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+
+		/* Set Rx Status */
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			IsBc = (FrameStat & XMR_FS_BC) != 0;
+			IsMc = (FrameStat & XMR_FS_MC) != 0;
+			IsBadFrame = (FrameStat &
+				(XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0;
+		} else {
+			IsBc = (FrameStat & GMR_FS_BC) != 0;
+			IsMc = (FrameStat & GMR_FS_MC) != 0;
+			IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) ||
+							((FrameStat & GMR_FS_RX_OK) == 0));
+		}
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Received frame of length %d on port %d\n",
+			FrameLength, PortIndex));
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Number of free rx descriptors: %d\n",
+			pRxPort->RxdRingFree));
+/* DumpMsg(pMsg, "Rx");	*/
+
+		if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID ||
+			(IsBadFrame)) {
+#if 0
+			(FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+#endif
+			/* there is a receive error in this frame */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS,
+				("skge: Error in received frame, dropped!\n"
+				"Control: %x\nRxStat: %x\n",
+				Control, FrameStat));
+
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+			pci_dma_sync_single(pAC->PciDev,
+						(dma_addr_t) PhysAddr,
+						FrameLength,
+						PCI_DMA_FROMDEVICE);
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+
+			continue;
+		}
+
+		/*
+		 * if short frame then copy data to reduce memory waste
+		 */
+		if ((FrameLength < SK_COPY_THRESHOLD) &&
+			((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) {
+			/*
+			 * Short frame detected and allocation successfull
+			 */
+			/* use new skb and copy data */
+			skb_reserve(pNewMsg, 2);
+			skb_put(pNewMsg, FrameLength);
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+			pci_dma_sync_single(pAC->PciDev,
+						(dma_addr_t) PhysAddr,
+						FrameLength,
+						PCI_DMA_FROMDEVICE);
+			eth_copy_and_sum(pNewMsg, pMsg->data,
+				FrameLength, 0);
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+			pMsg = pNewMsg;
+
+		}
+		else {
+			/*
+			 * if large frame, or SKB allocation failed, pass
+			 * the SKB directly to the networking
+			 */
+
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+			/* release the DMA mapping */
+			pci_unmap_single(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
+
+			/* set length in message */
+			skb_put(pMsg, FrameLength);
+			/* hardware checksum */
+			Type = ntohs(*((short*)&pMsg->data[12]));
+			if (Type == 0x800) {
+				Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff);
+				Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
+#if 0
+				if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) &&
+					(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) ||
+					(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+					Result = SkCsGetReceiveInfo(pAC,
+						&pMsg->data[14],
+						Csum1, Csum2, pRxPort->PortIndex);
+					if (Result ==
+						SKCS_STATUS_IP_FRAGMENT ||
+						Result ==
+						SKCS_STATUS_IP_CSUM_OK ||
+						Result ==
+						SKCS_STATUS_TCP_CSUM_OK ||
+						Result ==
+						SKCS_STATUS_UDP_CSUM_OK) {
+							pMsg->ip_summed =
+							CHECKSUM_UNNECESSARY;
+					} else {
+						SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+						SK_DBGCAT_DRV_RX_PROGRESS,
+						("skge: CRC error. Frame dropped!\n"));
+						goto rx_failed;
+					}
+				}/* checksumControl calculation valid */
+#endif
+			} /* IP frame */
+		} /* frame > SK_COPY_TRESHOLD */
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
+		ForRlmt = SK_RLMT_RX_PROTOCOL;
+#if 0
+		IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+#endif
+		SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+			IsBc, &Offset, &NumBytes);
+		if (NumBytes != 0) {
+#if 0
+			IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+#endif
+			SK_RLMT_LOOKAHEAD(pAC, PortIndex,
+				&pMsg->data[Offset],
+				IsBc, IsMc, &ForRlmt);
+		}
+		if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("W"));
+			/* send up only frames from active port */
+			if ((PortIndex == pAC->ActivePort) ||
+				(pAC->RlmtNets == 2)) {
+				/* frame for upper layer */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U"));
+#ifdef xDEBUG
+				DumpMsg(pMsg, "Rx");
+#endif
+				SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+					FrameLength, pRxPort->PortIndex);
+
+#if 0
+				pMsg->dev = pAC->dev[pRxPort->PortIndex];
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+#else
+				NetReceive(pMsg->data, pMsg->len);
+				dev_kfree_skb_any(pMsg);
+#endif
+			}
+			else {
+				/* drop frame */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("D"));
+				DEV_KFREE_SKB(pMsg);
+			}
+
+		} /* if not for rlmt */
+		else {
+			/* packet for rlmt */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+			pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+				pAC->IoBase, FrameLength);
+			if (pRlmtMbuf != NULL) {
+				pRlmtMbuf->pNext = NULL;
+				pRlmtMbuf->Length = FrameLength;
+				pRlmtMbuf->PortIdx = PortIndex;
+				EvPara.pParaPtr = pRlmtMbuf;
+				memcpy((char*)(pRlmtMbuf->pData),
+					   (char*)(pMsg->data),
+					   FrameLength);
+
+				/* SlowPathLock needed? */
+				if (SlowPathLock == SK_TRUE) {
+					spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+					spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+				} else {
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+				}
+
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("Q"));
+			}
+#if 0
+			if ((pAC->dev[pRxPort->PortIndex]->flags &
+				(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+				(ForRlmt & SK_RLMT_RX_PROTOCOL) ==
+				SK_RLMT_RX_PROTOCOL) {
+				pMsg->dev = pAC->dev[pRxPort->PortIndex];
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+			}
+#else
+			if (0) {
+			}
+#endif
+			else {
+				DEV_KFREE_SKB(pMsg);
+			}
+
+		} /* if packet for rlmt */
+	} /* for ... scanning the RXD ring */
+
+	/* RXD ring is empty -> fill and restart */
+	FillRxRing(pAC, pRxPort);
+	/* do not start if called from Close */
+	if (pAC->BoardLevel > 0) {
+		ClearAndStartRx(pAC, PortIndex);
+	}
+	return;
+
+rx_failed:
+	/* remove error frame */
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+		("Schrottdescriptor, length: 0x%x\n", FrameLength));
+
+	/* release the DMA mapping */
+
+	PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+	PhysAddr |= (SK_U64) pRxd->VDataLow;
+	pci_unmap_page(pAC->PciDev,
+			 PhysAddr,
+			 pAC->RxBufSize - 2,
+			 PCI_DMA_FROMDEVICE);
+	DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
+	pRxd->pMBuf = NULL;
+	pRxPort->RxdRingFree++;
+	pRxPort->pRxdRingHead = pRxd->pNextRxd;
+	goto rx_start;
+
+} /* ReceiveIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearAndStartRx - give a start receive command to BMU, clear IRQ
+ *
+ * Description:
+ *	This function sends a start command and a clear interrupt
+ *	command for one receive queue to the BMU.
+ *
+ * Returns: N/A
+ *	none
+ */
+static void ClearAndStartRx(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex)	/* index of the receive port (XMAC) */
+{
+	SK_OUT8(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CTRL,
+		RX_Q_CTRL_START | RX_Q_CTRL_CLR_I_EOF);
+} /* ClearAndStartRx */
+
+
+/*****************************************************************************
+ *
+ * 	ClearTxIrq - give a clear transmit IRQ command to BMU
+ *
+ * Description:
+ *	This function sends a clear tx IRQ command for one
+ *	transmit queue to the BMU.
+ *
+ * Returns: N/A
+ */
+static void ClearTxIrq(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex,	/* index of the transmit port (XMAC) */
+int	Prio)		/* priority or normal queue */
+{
+	SK_OUT8(pAC->IoBase, TxQueueAddr[PortIndex][Prio]+TX_Q_CTRL,
+		TX_Q_CTRL_CLR_I_EOF);
+} /* ClearTxIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearRxRing - remove all buffers from the receive ring
+ *
+ * Description:
+ *	This function removes all receive buffers from the ring.
+ *	The receive BMU must be stopped before calling this function.
+ *
+ * Returns: N/A
+ */
+static void ClearRxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+RX_PORT	*pRxPort)	/* pointer to rx port struct */
+{
+RXD		*pRxd;	/* pointer to the current descriptor */
+unsigned long	Flags;
+SK_U64		PhysAddr;
+
+	if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
+		return;
+	}
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	pRxd = pRxPort->pRxdRingHead;
+	do {
+		if (pRxd->pMBuf != NULL) {
+
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+			pci_unmap_page(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
+			DEV_KFREE_SKB(pRxd->pMBuf);
+			pRxd->pMBuf = NULL;
+		}
+		pRxd->RBControl &= RX_CTRL_OWN_BMU;
+		pRxd = pRxd->pNextRxd;
+		pRxPort->RxdRingFree++;
+	} while (pRxd != pRxPort->pRxdRingTail);
+	pRxPort->pRxdRingTail = pRxPort->pRxdRingHead;
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* ClearRxRing */
+
+
+/*****************************************************************************
+ *
+ *	ClearTxRing - remove all buffers from the transmit ring
+ *
+ * Description:
+ *	This function removes all transmit buffers from the ring.
+ *	The transmit BMU must be stopped before calling this function
+ *	and transmitting at the upper level must be disabled.
+ *	The BMU own bit of all descriptors is cleared, the rest is
+ *	done by calling FreeTxDescriptors.
+ *
+ * Returns: N/A
+ */
+static void ClearTxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+TX_PORT	*pTxPort)	/* pointer to tx prt struct */
+{
+TXD		*pTxd;		/* pointer to the current descriptor */
+int		i;
+unsigned long	Flags;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+	pTxd = pTxPort->pTxdRingHead;
+	for (i=0; i<pAC->TxDescrPerRing; i++) {
+		pTxd->TBControl &= ~TX_CTRL_OWN_BMU;
+		pTxd = pTxd->pNextTxd;
+	}
+	FreeTxDescriptors(pAC, pTxPort);
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+} /* ClearTxRing */
+
+
+#if 0
+/*****************************************************************************
+ *
+ * 	SetQueueSizes - configure the sizes of rx and tx queues
+ *
+ * Description:
+ *	This function assigns the sizes for active and passive port
+ *	to the appropriate HWinit structure variables.
+ *	The passive port(s) get standard values, all remaining RAM
+ *	is given to the active port.
+ *	The queue sizes are in kbyte and must be multiple of 8.
+ *	The limits for the number of buffers filled into the rx rings
+ *	is also set in this routine.
+ *
+ * Returns:
+ *	none
+ */
+static void SetQueueSizes(
+SK_AC	*pAC)	/* pointer to the adapter context */
+{
+int	StandbyRam;	/* adapter RAM used for a standby port */
+int	RemainingRam;	/* adapter RAM available for the active port */
+int	RxRam;		/* RAM used for the active port receive queue */
+int	i;		/* loop counter */
+
+if (pAC->RlmtNets == 1) {
+	StandbyRam = SK_RLMT_STANDBY_QRXSIZE + SK_RLMT_STANDBY_QXASIZE +
+		SK_RLMT_STANDBY_QXSSIZE;
+	RemainingRam = pAC->GIni.GIRamSize -
+		(pAC->GIni.GIMacsFound-1) * StandbyRam;
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->GIni.GP[i].PRxQSize = SK_RLMT_STANDBY_QRXSIZE;
+		pAC->GIni.GP[i].PXSQSize = SK_RLMT_STANDBY_QXSSIZE;
+		pAC->GIni.GP[i].PXAQSize = SK_RLMT_STANDBY_QXASIZE;
+	}
+	RxRam = (RemainingRam * 8 / 10) & ~7;
+	pAC->GIni.GP[pAC->ActivePort].PRxQSize = RxRam;
+	pAC->GIni.GP[pAC->ActivePort].PXSQSize = 0;
+	pAC->GIni.GP[pAC->ActivePort].PXAQSize =
+		(RemainingRam - RxRam) & ~7;
+	pAC->RxQueueSize = RxRam;
+	pAC->TxSQueueSize = 0;
+	pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7;
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("queue sizes settings - rx:%d  txA:%d txS:%d\n",
+		pAC->RxQueueSize,pAC->TxAQueueSize, pAC->TxSQueueSize));
+} else {
+	RemainingRam = pAC->GIni.GIRamSize/pAC->GIni.GIMacsFound;
+	RxRam = (RemainingRam * 8 / 10) & ~7;
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->GIni.GP[i].PRxQSize = RxRam;
+		pAC->GIni.GP[i].PXSQSize = 0;
+		pAC->GIni.GP[i].PXAQSize = (RemainingRam - RxRam) & ~7;
+	}
+
+	pAC->RxQueueSize = RxRam;
+	pAC->TxSQueueSize = 0;
+	pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7;
+}
+	for (i=0; i<SK_MAX_MACS; i++) {
+		pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing;
+	}
+
+	if (pAC->RlmtNets == 2) {
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+		}
+	} else {
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+		}
+		/*
+		 * Do not set the Limit to 0, because this could cause
+		 * wrap around with ReQueue'ed buffers (a buffer could
+		 * be requeued in the same position, made accessable to
+		 * the hardware, and the hardware could change its
+		 * contents!
+		 */
+		pAC->RxPort[pAC->ActivePort].RxFillLimit = 1;
+	}
+
+#ifdef DEBUG
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("i: %d,  RxQSize: %d,  PXSQsize: %d, PXAQSize: %d\n",
+			i,
+			pAC->GIni.GP[i].PRxQSize,
+			pAC->GIni.GP[i].PXSQSize,
+			pAC->GIni.GP[i].PXAQSize));
+	}
+#endif
+} /* SetQueueSizes */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeSetMacAddr - Set the hardware MAC address
+ *
+ * Description:
+ *	This function sets the MAC address used by the adapter.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p)
+{
+
+DEV_NET *pNet = (DEV_NET*) dev->priv;
+SK_AC	*pAC = pNet->pAC;
+
+struct sockaddr	*addr = p;
+unsigned long	Flags;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetMacAddr starts now...\n"));
+	if(netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	if (pAC->RlmtNets == 2)
+		SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+	else
+		SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	return 0;
+} /* SkGeSetMacAddr */
+#endif
+
+
+/*****************************************************************************
+ *
+ * 	SkGeSetRxMode - set receive mode
+ *
+ * Description:
+ *	This function sets the receive mode of an adapter. The adapter
+ *	supports promiscuous mode, allmulticast mode and a number of
+ *	multicast addresses. If more multicast addresses the available
+ *	are selected, a hash function in the hardware is used.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+#if 0
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev)
+{
+
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
+struct dev_mc_list	*pMcList;
+int			i;
+int			PortIdx;
+unsigned long		Flags;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetRxMode starts now... "));
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (dev->flags & IFF_PROMISC) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("PROMISCUOUS mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_LLC);
+	} else if (dev->flags & IFF_ALLMULTI) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("ALLMULTI mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_ALL_MC);
+	} else {
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_NONE);
+		SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("Number of MC entries: %d ", dev->mc_count));
+
+		pMcList = dev->mc_list;
+		for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
+			SkAddrMcAdd(pAC, pAC->IoBase, PortIdx,
+				(SK_MAC_ADDR*)pMcList->dmi_addr, 0);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
+				("%02x:%02x:%02x:%02x:%02x:%02x\n",
+				pMcList->dmi_addr[0],
+				pMcList->dmi_addr[1],
+				pMcList->dmi_addr[2],
+				pMcList->dmi_addr[3],
+				pMcList->dmi_addr[4],
+				pMcList->dmi_addr[5]));
+		}
+		SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	return;
+} /* SkGeSetRxMode */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeChangeMtu - set the MTU to another value
+ *
+ * Description:
+ *	This function sets is called whenever the MTU size is changed
+ *	(ifconfig mtu xxx dev ethX). If the MTU is bigger than standard
+ *	ethernet MTU size, long frame support is activated.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
+{
+DEV_NET		*pNet;
+DEV_NET		*pOtherNet;
+SK_AC		*pAC;
+unsigned long	Flags;
+int		i;
+SK_EVPARA 	EvPara;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeChangeMtu starts now...\n"));
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
+		return -EINVAL;
+	}
+
+	if(pAC->BoardLevel != 2) {
+		return -EINVAL;
+	}
+
+	pNet->Mtu = NewMtu;
+	pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv;
+	if ((pOtherNet->Mtu > 1500) && (NewMtu <= 1500) && (pOtherNet->Up==1)) {
+		return(0);
+	}
+
+	EvPara.Para32[0] = pNet->NetNr;
+	EvPara.Para32[1] = -1;
+
+	pAC->RxBufSize = NewMtu + 32;
+	dev->mtu = NewMtu;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("New MTU: %d\n", NewMtu));
+
+	/* prevent reconfiguration while changing the MTU */
+
+	/* disable interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	/* Found more than one port */
+	if ((pAC->GIni.GIMacsFound == 2 ) &&
+		(pAC->RlmtNets == 2)) {
+			/* Stop both ports */
+			EvPara.Para32[0] = 0;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			EvPara.Para32[0] = 1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	}
+
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		spin_lock_irqsave(
+			&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags);
+		netif_stop_queue(pAC->dev[i]);
+
+	}
+
+	/*
+	 * adjust number of rx buffers allocated
+	 */
+	if (NewMtu > 1500) {
+		/* use less rx buffers */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			/* Found more than one port */
+			if ((pAC->GIni.GIMacsFound == 2 ) &&
+				(pAC->RlmtNets == 2)) {
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 100;
+			} else {
+				if (i == pAC->ActivePort)
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 100;
+				else
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 10;
+			}
+		}
+	}
+	else {
+		/* use normal amount of rx buffers */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			/* Found more than one port */
+			if ((pAC->GIni.GIMacsFound == 2 ) &&
+				(pAC->RlmtNets == 2)) {
+					pAC->RxPort[i].RxFillLimit = 1;
+			} else {
+				if (i == pAC->ActivePort)
+					pAC->RxPort[i].RxFillLimit = 1;
+				else
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 100;
+			}
+		}
+	}
+
+	SkGeDeInit(pAC, pAC->IoBase);
+
+	/*
+	 * enable/disable hardware support for long frames
+	 */
+	if (NewMtu > 1500) {
+/*		pAC->JumboActivated = SK_TRUE; /#* is never set back !!! */
+		pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
+	}
+	else {
+		if ((pAC->GIni.GIMacsFound == 2 ) &&
+			(pAC->RlmtNets == 2)) {
+			pAC->GIni.GIPortUsage = SK_MUL_LINK;
+		} else {
+			pAC->GIni.GIPortUsage = SK_RED_LINK;
+		}
+	}
+
+	SkGeInit(   pAC, pAC->IoBase, 1);
+	SkI2cInit(  pAC, pAC->IoBase, 1);
+	SkEventInit(pAC, pAC->IoBase, 1);
+	SkPnmiInit( pAC, pAC->IoBase, 1);
+	SkAddrInit( pAC, pAC->IoBase, 1);
+	SkRlmtInit( pAC, pAC->IoBase, 1);
+	SkTimerInit(pAC, pAC->IoBase, 1);
+
+	/*
+	 * tschilling:
+	 * Speed and others are set back to default in level 1 init!
+	 */
+	GetConfiguration(pAC);
+
+	SkGeInit(   pAC, pAC->IoBase, 2);
+	SkI2cInit(  pAC, pAC->IoBase, 2);
+	SkEventInit(pAC, pAC->IoBase, 2);
+	SkPnmiInit( pAC, pAC->IoBase, 2);
+	SkAddrInit( pAC, pAC->IoBase, 2);
+	SkRlmtInit( pAC, pAC->IoBase, 2);
+	SkTimerInit(pAC, pAC->IoBase, 2);
+
+	/*
+	 * clear and reinit the rx rings here
+	 */
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+		ClearRxRing(pAC, &pAC->RxPort[i]);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+
+		/* Enable transmit descriptor polling. */
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	};
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+#ifdef USE_INT_MOD
+	{
+		unsigned long ModBase;
+		ModBase = 53125000 / INTS_PER_SEC;
+		SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+		SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK);
+		SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+	}
+#endif
+
+	netif_start_queue(pAC->dev[pNet->PortNr]);
+	for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
+		spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+	}
+
+	/* enable Interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+	/* Found more than one port */
+	if ((pAC->GIni.GIMacsFound == 2 ) &&
+		(pAC->RlmtNets == 2)) {
+			/* Start both ports */
+			EvPara.Para32[0] = pAC->RlmtNets;
+			EvPara.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+				EvPara);
+
+
+			EvPara.Para32[1] = -1;
+			EvPara.Para32[0] = pNet->PortNr;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+
+			if (pOtherNet->Up) {
+				EvPara.Para32[0] = pOtherNet->PortNr;
+				SkEventQueue(pAC, SKGE_RLMT,
+					SK_RLMT_START, EvPara);
+			}
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	}
+
+	SkEventDispatcher(pAC, pAC->IoBase);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	return 0;
+} /* SkGeChangeMtu */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeStats - return ethernet device statistics
+ *
+ * Description:
+ *	This function return statistic data about the ethernet device
+ *	to the operating system.
+ *
+ * Returns:
+ *	pointer to the statistic structure.
+ */
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev)
+{
+DEV_NET *pNet = (DEV_NET*) dev->priv;
+SK_AC	*pAC = pNet->pAC;
+SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
+SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */
+SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
+unsigned int    Size;                   /* size of pnmi struct */
+unsigned long	Flags;			/* for spin lock */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeStats starts now...\n"));
+	pPnmiStruct = &pAC->PnmiStruct;
+	memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	Size = SK_PNMI_STRUCT_SIZE;
+		SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	pPnmiStat = &pPnmiStruct->Stat[0];
+	pPnmiConf = &pPnmiStruct->Conf[0];
+
+	pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF;
+	pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
+	pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
+	pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
+
+	if (pNet->Mtu <= 1500) {
+		pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+	} else {
+		pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
+			pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF);
+	}
+
+
+	if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12)
+		pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts;
+
+	pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+	pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF;
+	pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+
+	/* detailed rx_errors: */
+	pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF;
+	pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF;
+	pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF;
+	pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF;
+
+	/* detailed tx_errors */
+	pAC->stats.tx_aborted_errors = (SK_U32) 0;
+	pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF;
+	pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_window_errors = (SK_U32) 0;
+
+	return(&pAC->stats);
+} /* SkGeStats */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIoctl - IO-control function
+ *
+ * Description:
+ *	This function is called if an ioctl is issued on the device.
+ *	There are three subfunction for reading, writing and test-writing
+ *	the private MIB data structure (usefull for SysKonnect-internal tools).
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd)
+{
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
+SK_GE_IOCTL	Ioctl;
+unsigned int	Err = 0;
+int		Size;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIoctl starts now...\n"));
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
+		return -EFAULT;
+	}
+
+	switch(cmd) {
+	case SK_IOCTL_SETMIB:
+	case SK_IOCTL_PRESETMIB:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	case SK_IOCTL_GETMIB:
+		if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData,
+			Ioctl.Len<sizeof(pAC->PnmiStruct)?
+			Ioctl.Len : sizeof(pAC->PnmiStruct))) {
+			return -EFAULT;
+		}
+		Size = SkGeIocMib(pNet, Ioctl.Len, cmd);
+		if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
+			Ioctl.Len<Size? Ioctl.Len : Size)) {
+			return -EFAULT;
+		}
+		Ioctl.Len = Size;
+		if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+			return -EFAULT;
+		}
+		break;
+	default:
+		Err = -EOPNOTSUPP;
+	}
+	return(Err);
+} /* SkGeIoctl */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message
+ *
+ * Description:
+ *	This function reads/writes the MIB data using PNMI (Private Network
+ *	Management Interface).
+ *	The destination for the data must be provided with the
+ *	ioctl call and is given to the driver in the form of
+ *	a user space address.
+ *	Copying from the user-provided data area into kernel messages
+ *	and back is done by copy_from_user and copy_to_user calls in
+ *	SkGeIoctl.
+ *
+ * Returns:
+ *	returned size from PNMI call
+ */
+static int SkGeIocMib(
+DEV_NET		*pNet,	/* pointer to the adapter context */
+unsigned int	Size,	/* length of ioctl data */
+int		mode)	/* flag for set/preset */
+{
+unsigned long	Flags;	/* for spin lock */
+SK_AC		*pAC;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIocMib starts now...\n"));
+	pAC = pNet->pAC;
+	/* access MIB */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	switch(mode) {
+	case SK_IOCTL_GETMIB:
+		SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	case SK_IOCTL_PRESETMIB:
+		SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	case SK_IOCTL_SETMIB:
+		SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("MIB data access succeeded\n"));
+	return (Size);
+} /* SkGeIocMib */
+#endif
+
+
+/*****************************************************************************
+ *
+ * 	GetConfiguration - read configuration information
+ *
+ * Description:
+ *	This function reads per-adapter configuration information from
+ *	the options provided on the command line.
+ *
+ * Returns:
+ *	none
+ */
+static void GetConfiguration(
+SK_AC	*pAC)	/* pointer to the adapter context structure */
+{
+SK_I32	Port;		/* preferred port */
+int	LinkSpeed;	/* Link speed */
+int	AutoNeg;	/* auto negotiation off (0) or on (1) */
+int	DuplexCap;	/* duplex capabilities (0=both, 1=full, 2=half */
+int	MSMode;		/* master / slave mode selection */
+SK_BOOL	AutoSet;
+SK_BOOL DupSet;
+/*
+ *	The two parameters AutoNeg. and DuplexCap. map to one configuration
+ *	parameter. The mapping is described by this table:
+ *	DuplexCap ->	|	both	|	full	|	half	|
+ *	AutoNeg		|		|		|		|
+ *	-----------------------------------------------------------------
+ *	Off		|    illegal	|	Full	|	Half	|
+ *	-----------------------------------------------------------------
+ *	On		|   AutoBoth	|   AutoFull	|   AutoHalf	|
+ *	-----------------------------------------------------------------
+ *	Sense		|   AutoSense	|   AutoSense	|   AutoSense	|
+ */
+int	Capabilities[3][3] =
+		{ {		  -1, SK_LMODE_FULL,     SK_LMODE_HALF},
+		  {SK_LMODE_AUTOBOTH, SK_LMODE_AUTOFULL, SK_LMODE_AUTOHALF},
+		  {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} };
+#define DC_BOTH	0
+#define DC_FULL 1
+#define DC_HALF 2
+#define AN_OFF	0
+#define AN_ON	1
+#define AN_SENS	2
+
+	/* settings for port A */
+	/* settings link speed */
+	LinkSpeed = SK_LSPEED_AUTO; 	/* default: do auto select */
+	if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_A[pAC->Index] != NULL) {
+		if (strcmp(Speed_A[pAC->Index],"")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"Auto")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"10")==0) {
+			LinkSpeed = SK_LSPEED_10MBPS;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"100")==0) {
+			LinkSpeed = SK_LSPEED_100MBPS;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"1000")==0) {
+			LinkSpeed = SK_LSPEED_1000MBPS;
+		}
+		else printk("%s: Illegal value for Speed_A\n",
+			pAC->dev[0]->name);
+	}
+
+	/* Check speed parameter */
+	/* Only copper type adapter and GE V2 cards */
+	if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) ||
+		(pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) &&
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("%s: Illegal value for Speed_A. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n", pAC->dev[0]->name);
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+	pAC->GIni.GP[0].PLinkSpeed = LinkSpeed;
+
+	/* Autonegotiation */
+	AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_A[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_A[pAC->Index],"")==0) {
+			AutoSet = SK_FALSE;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) {
+			AutoNeg = AN_ON;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) {
+			AutoNeg = AN_OFF;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
+			AutoNeg = AN_SENS;
+		}
+		else printk("%s: Illegal value for AutoNeg_A\n",
+			pAC->dev[0]->name);
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet = SK_FALSE;
+	if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_A[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_A[pAC->Index],"")==0) {
+			DupSet = SK_FALSE;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Both")==0) {
+			DuplexCap = DC_BOTH;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Full")==0) {
+			DuplexCap = DC_FULL;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
+			DuplexCap = DC_HALF;
+		}
+		else printk("%s: Illegal value for DupCap_A\n",
+			pAC->dev[0]->name);
+	}
+
+	/* check for illegal combinations */
+	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("%s, Port A: DuplexCapabilities"
+			" ignored using Sense mode\n", pAC->dev[0]->name);
+	}
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("%s, Port A: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n", pAC->dev[0]->name);
+
+		DuplexCap = DC_FULL;
+	}
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+
+	if (!AutoSet && DupSet) {
+		printk("%s, Port A: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n",
+			pAC->dev[0]->name);
+		AutoNeg = AN_ON;
+	}
+
+	/* set the desired mode */
+	pAC->GIni.GP[0].PLinkModeConf =
+		Capabilities[AutoNeg][DuplexCap];
+
+	pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+	if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_A[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) {
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_SYM_OR_REM;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_SYMMETRIC;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_LOC_SEND;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_NONE;
+		}
+		else printk("Illegal value for FlowCtrl_A\n");
+	}
+	if (AutoNeg==AN_OFF && pAC->GIni.GP[0].PFlowCtrlMode!=
+		SK_FLOW_MODE_NONE) {
+		printk("%s, Port A: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n", pAC->dev[0]->name);
+		pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE;
+	}
+
+	MSMode = SK_MS_MODE_AUTO; /* default: do auto select */
+	if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_A[pAC->Index] != NULL) {
+		if (strcmp(Role_A[pAC->Index],"")==0) {
+		}
+		else if (strcmp(Role_A[pAC->Index],"Auto")==0) {
+			MSMode = SK_MS_MODE_AUTO;
+		}
+		else if (strcmp(Role_A[pAC->Index],"Master")==0) {
+			MSMode = SK_MS_MODE_MASTER;
+		}
+		else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
+			MSMode = SK_MS_MODE_SLAVE;
+		}
+		else printk("%s: Illegal value for Role_A\n",
+			pAC->dev[0]->name);
+	}
+	pAC->GIni.GP[0].PMSMode = MSMode;
+
+
+	/* settings for port B */
+	/* settings link speed */
+	LinkSpeed = SK_LSPEED_AUTO; 	/* default: do auto select */
+	if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_B[pAC->Index] != NULL) {
+		if (strcmp(Speed_B[pAC->Index],"")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"Auto")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"10")==0) {
+			LinkSpeed = SK_LSPEED_10MBPS;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"100")==0) {
+			LinkSpeed = SK_LSPEED_100MBPS;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"1000")==0) {
+			LinkSpeed = SK_LSPEED_1000MBPS;
+		}
+		else printk("%s: Illegal value for Speed_B\n",
+			pAC->dev[1]->name);
+	}
+
+	/* Check speed parameter */
+	/* Only copper type adapter and GE V2 cards */
+	if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) ||
+		(pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) &&
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("%s: Illegal value for Speed_B. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n", pAC->dev[1]->name);
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+	pAC->GIni.GP[1].PLinkSpeed = LinkSpeed;
+
+	/* Auto negotiation */
+	AutoNeg = AN_SENS; /* default: do auto Sense */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_B[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_B[pAC->Index],"")==0) {
+			AutoSet = SK_FALSE;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) {
+			AutoNeg = AN_ON;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) {
+			AutoNeg = AN_OFF;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
+			AutoNeg = AN_SENS;
+		}
+		else printk("Illegal value for AutoNeg_B\n");
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet = SK_FALSE;
+	if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_B[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_B[pAC->Index],"")==0) {
+			DupSet = SK_FALSE;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Both")==0) {
+			DuplexCap = DC_BOTH;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Full")==0) {
+			DuplexCap = DC_FULL;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
+			DuplexCap = DC_HALF;
+		}
+		else printk("Illegal value for DupCap_B\n");
+	}
+
+	/* check for illegal combinations */
+	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("%s, Port B: DuplexCapabilities"
+			" ignored using Sense mode\n", pAC->dev[1]->name);
+	}
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("%s, Port B: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n", pAC->dev[1]->name);
+
+		DuplexCap = DC_FULL;
+	}
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+
+	if (!AutoSet && DupSet) {
+		printk("%s, Port B: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n",
+			pAC->dev[1]->name);
+		AutoNeg = AN_ON;
+	}
+
+	/* set the desired mode */
+	pAC->GIni.GP[1].PLinkModeConf =
+		Capabilities[AutoNeg][DuplexCap];
+
+	pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+	if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_B[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) {
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_SYM_OR_REM;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_SYMMETRIC;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_LOC_SEND;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_NONE;
+		}
+		else printk("Illegal value for FlowCtrl_B\n");
+	}
+	if (AutoNeg==AN_OFF && pAC->GIni.GP[1].PFlowCtrlMode!=
+		SK_FLOW_MODE_NONE) {
+		printk("%s, Port B: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n", pAC->dev[1]->name);
+		pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE;
+	}
+
+	MSMode = SK_MS_MODE_AUTO; /* default: do auto select */
+	if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_B[pAC->Index] != NULL) {
+		if (strcmp(Role_B[pAC->Index],"")==0) {
+		}
+		else if (strcmp(Role_B[pAC->Index],"Auto")==0) {
+			MSMode = SK_MS_MODE_AUTO;
+		}
+		else if (strcmp(Role_B[pAC->Index],"Master")==0) {
+			MSMode = SK_MS_MODE_MASTER;
+		}
+		else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
+			MSMode = SK_MS_MODE_SLAVE;
+		}
+		else printk("%s: Illegal value for Role_B\n",
+			pAC->dev[1]->name);
+	}
+	pAC->GIni.GP[1].PMSMode = MSMode;
+
+
+	/* settings for both ports */
+	pAC->ActivePort = 0;
+	if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		PrefPort[pAC->Index] != NULL) {
+		if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
+			pAC->ActivePort = 0;
+			pAC->Rlmt.Net[0].Preference = -1; /* auto */
+			pAC->Rlmt.Net[0].PrefPort = 0;
+		}
+		else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
+			/*
+			 * do not set ActivePort here, thus a port
+			 * switch is issued after net up.
+			 */
+			Port = 0;
+			pAC->Rlmt.Net[0].Preference = Port;
+			pAC->Rlmt.Net[0].PrefPort = Port;
+		}
+		else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
+			/*
+			 * do not set ActivePort here, thus a port
+			 * switch is issued after net up.
+			 */
+			Port = 1;
+			pAC->Rlmt.Net[0].Preference = Port;
+			pAC->Rlmt.Net[0].PrefPort = Port;
+		}
+		else printk("%s: Illegal value for PrefPort\n",
+			pAC->dev[0]->name);
+	}
+
+	pAC->RlmtNets = 1;
+
+	if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		RlmtMode[pAC->Index] != NULL) {
+		if (strcmp(RlmtMode[pAC->Index], "") == 0) {
+			pAC->RlmtMode = 0;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+				SK_RLMT_CHECK_LOC_LINK;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+				SK_RLMT_CHECK_LOC_LINK |
+				SK_RLMT_CHECK_SEG;
+		}
+		else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) &&
+			(pAC->GIni.GIMacsFound == 2)) {
+				pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+				pAC->RlmtNets = 2;
+		}
+		else {
+			printk("%s: Illegal value for"
+				" RlmtMode, using default\n", pAC->dev[0]->name);
+			pAC->RlmtMode = 0;
+		}
+	}
+	else {
+		pAC->RlmtMode = 0;
+	}
+} /* GetConfiguration */
+
+
+/*****************************************************************************
+ *
+ * 	ProductStr - return a adapter identification string from vpd
+ *
+ * Description:
+ *	This function reads the product name string from the vpd area
+ *	and puts it the field pAC->DeviceString.
+ *
+ * Returns: N/A
+ */
+static void ProductStr(
+SK_AC	*pAC		/* pointer to adapter context */
+)
+{
+int	StrLen = 80;		/* length of the string, defined in SK_AC */
+char	Keyword[] = VPD_NAME;	/* vpd productname identifier */
+int	ReturnCode;		/* return code from vpd_read */
+unsigned long Flags;
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
+		&StrLen);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	if (ReturnCode != 0) {
+		/* there was an error reading the vpd data */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+			("Error reading VPD data: %d\n", ReturnCode));
+		pAC->DeviceStr[0] = '\0';
+	}
+} /* ProductStr */
+
+
+/****************************************************************************/
+/* functions for common modules *********************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	SkDrvAllocRlmtMbuf - allocate an RLMT mbuf
+ *
+ * Description:
+ *	This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure
+ *	is embedded into a socket buff data area.
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	NULL or pointer to Mbuf.
+ */
+SK_MBUF *SkDrvAllocRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */
+SK_IOC		IoC,		/* the IO-context */
+unsigned	BufferSize)	/* size of the requested buffer */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a new rlmt-mbuf structure */
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+
+	pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		return (NULL);
+	}
+	pRlmtMbuf = (SK_MBUF*) pMsgBlock->data;
+	skb_reserve(pMsgBlock, sizeof(SK_MBUF));
+	pRlmtMbuf->pNext = NULL;
+	pRlmtMbuf->pOs = pMsgBlock;
+	pRlmtMbuf->pData = pMsgBlock->data;	/* Data buffer. */
+	pRlmtMbuf->Size = BufferSize;		/* Data buffer size. */
+	pRlmtMbuf->Length = 0;		/* Length of packet (<= Size). */
+	return (pRlmtMbuf);
+
+} /* SkDrvAllocRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvFreeRlmtMbuf - free an RLMT mbuf
+ *
+ * Description:
+ *	This routine frees one or more RLMT mbuf(s).
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	Nothing
+ */
+void  SkDrvFreeRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */
+SK_IOC		IoC,		/* the IO-context */
+SK_MBUF		*pMbuf)		/* size of the requested buffer */
+{
+SK_MBUF		*pFreeMbuf;
+SK_MBUF		*pNextMbuf;
+
+	pFreeMbuf = pMbuf;
+	do {
+		pNextMbuf = pFreeMbuf->pNext;
+		DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
+		pFreeMbuf = pNextMbuf;
+	} while ( pFreeMbuf != NULL );
+} /* SkDrvFreeRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkOsGetTime - provide a time value
+ *
+ * Description:
+ *	This routine provides a time value. The unit is 1/HZ (defined by Linux).
+ *	It is not used for absolute time, but only for time differences.
+ *
+ *
+ * Returns:
+ *	Time value
+ */
+SK_U64 SkOsGetTime(SK_AC *pAC)
+{
+#if 0
+	return jiffies;
+#else
+	return get_timer(0);
+#endif
+} /* SkOsGetTime */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgDWord - read a 32 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 32 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgDWord(
+SK_AC *pAC,		/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_dword(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgWord - read a 16 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 16 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_word(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgByte - read a 8 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 8 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_byte(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgDWord - write a 32 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 32 bit value to the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgDWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 Val)		/* pointer to store the read value */
+{
+	pci_write_config_dword(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 16 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 16 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 Val)		/* pointer to store the read value */
+{
+	pci_write_config_word(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 8 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 8 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 Val)		/* pointer to store the read value */
+{
+	pci_write_config_byte(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvEvent - handle driver events
+ *
+ * Description:
+ *	This function handles events from all modules directed to the driver
+ *
+ * Context:
+ *	Is called under protection of slow path lock.
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *
+ */
+int SkDrvEvent(
+SK_AC *pAC,		/* pointer to adapter context */
+SK_IOC IoC,		/* io-context */
+SK_U32 Event,		/* event-id */
+SK_EVPARA Param)	/* event-parameter */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a rlmt-mbuf structure */
+struct sk_buff	*pMsg;		/* pointer to a message block */
+int		FromPort;	/* the port from which we switch away */
+int		ToPort;		/* the port we switch to */
+SK_EVPARA	NewPara;	/* parameter for further events */
+#if 0
+int		Stat;
+#endif
+unsigned long	Flags;
+SK_BOOL		DualNet;
+
+	switch (Event) {
+	case SK_DRV_ADAP_FAIL:
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("ADAPTER FAIL EVENT\n"));
+		printk("%s: Adapter failed.\n", pAC->dev[0]->name);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_FAIL:
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT FAIL EVENT, Port: %d\n", FromPort));
+		if (FromPort == 0) {
+			printk("%s: Port A failed.\n", pAC->dev[0]->name);
+		} else {
+			printk("%s: Port B failed.\n", pAC->dev[1]->name);
+		}
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_RESET:	 /* SK_U32 PortIdx */
+		/* action list 4 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT RESET EVENT, Port: %d ", FromPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+#if 0
+		pAC->dev[Param.Para32[0]]->flags &= ~IFF_RUNNING;
+#endif
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		/* clear rx ring from received frames */
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
+
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		/* tschilling: Handling of return value inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort)) {
+			if (FromPort == 0) {
+				printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name);
+			} else {
+				printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name);
+			}
+		}
+		SkAddrMcUpdate(pAC,IoC, FromPort);
+		PortReInitBmu(pAC, FromPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_NET_UP:	 /* SK_U32 PortIdx */
+		/* action list 5 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET UP EVENT, Port: %d ", Param.Para32[0]));
+#ifdef SK98_INFO
+		printk("%s: network connection up using"
+			" port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
+
+		/* tschilling: Values changed according to LinkSpeedUsed. */
+		Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed;
+		if (Stat == SK_LSPEED_STAT_10MBPS) {
+			printk("    speed:           10\n");
+		} else if (Stat == SK_LSPEED_STAT_100MBPS) {
+			printk("    speed:           100\n");
+		} else if (Stat == SK_LSPEED_STAT_1000MBPS) {
+			printk("    speed:           1000\n");
+		} else {
+			printk("    speed:           unknown\n");
+		}
+
+		Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_AUTOFULL) {
+			printk("    autonegotiation: yes\n");
+		}
+		else {
+			printk("    autonegotiation: no\n");
+		}
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_HALF) {
+			printk("    duplex mode:     half\n");
+		}
+		else {
+			printk("    duplex mode:     full\n");
+		}
+		Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
+		if (Stat == SK_FLOW_STAT_REM_SEND ) {
+			printk("    flowctrl:        remote send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_LOC_SEND ){
+			printk("    flowctrl:        local send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
+			printk("    flowctrl:        symmetric\n");
+		}
+		else {
+			printk("    flowctrl:        none\n");
+		}
+
+		/* tschilling: Check against CopperType now. */
+		if ((pAC->GIni.GICopperType == SK_TRUE) &&
+			(pAC->GIni.GP[FromPort].PLinkSpeedUsed ==
+			SK_LSPEED_STAT_1000MBPS)) {
+			Stat = pAC->GIni.GP[FromPort].PMSStatus;
+			if (Stat == SK_MS_STAT_MASTER ) {
+				printk("    role:            master\n");
+			}
+			else if (Stat == SK_MS_STAT_SLAVE ) {
+				printk("    role:            slave\n");
+			}
+			else {
+				printk("    role:            ???\n");
+			}
+		}
+
+#ifdef SK_ZEROCOPY
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON)
+			printk("    scatter-gather:  enabled\n");
+		else
+			printk("    scatter-gather:  disabled\n");
+
+#else
+			printk("    scatter-gather:  disabled\n");
+#endif
+#endif /* SK98_INFO */
+
+		if ((Param.Para32[0] != pAC->ActivePort) &&
+			(pAC->RlmtNets == 1)) {
+			NewPara.Para32[0] = pAC->ActivePort;
+			NewPara.Para32[1] = Param.Para32[0];
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
+				NewPara);
+		}
+
+		/* Inform the world that link protocol is up. */
+#if 0
+		pAC->dev[Param.Para32[0]]->flags |= IFF_RUNNING;
+#endif
+
+		break;
+	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
+		/* action list 7 */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET DOWN EVENT "));
+#ifdef SK98_INFO
+		printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name);
+#endif
+#if 0
+		pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING;
+#endif
+		break;
+	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH HARD "));
+	case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+	/* action list 6 */
+		printk("%s: switching to port %c\n", pAC->dev[0]->name,
+			'A'+Param.Para32[1]);
+	case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		FromPort = Param.Para32[0];
+		ToPort = Param.Para32[1];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH EVENT, From: %d  To: %d (Pref %d) ",
+			FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		NewPara.Para64 = ToPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		spin_lock_irqsave(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST);
+		SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */
+		ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */
+
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		spin_lock_irqsave(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		pAC->ActivePort = ToPort;
+#if 0
+		SetQueueSizes(pAC);
+#else
+		/* tschilling: New common function with minimum size check. */
+		DualNet = SK_FALSE;
+		if (pAC->RlmtNets == 2) {
+			DualNet = SK_TRUE;
+		}
+
+		if (SkGeInitAssignRamToQueues(
+			pAC,
+			pAC->ActivePort,
+			DualNet)) {
+			spin_unlock_irqrestore(
+				&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+			spin_unlock_irqrestore(
+				&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+				Flags);
+			printk("SkGeInitAssignRamToQueues failed.\n");
+			break;
+		}
+#endif
+		/* tschilling: Handling of return values inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort) ||
+			SkGeInitPort(pAC, IoC, ToPort)) {
+			printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name);
+		}
+		if (Event == SK_DRV_SWITCH_SOFT) {
+			SkMacRxTxEnable(pAC, IoC, FromPort);
+		}
+		SkMacRxTxEnable(pAC, IoC, ToPort);
+		SkAddrSwap(pAC, IoC, FromPort, ToPort);
+		SkAddrMcUpdate(pAC, IoC, FromPort);
+		SkAddrMcUpdate(pAC, IoC, ToPort);
+		PortReInitBmu(pAC, FromPort);
+		PortReInitBmu(pAC, ToPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		SkGePollTxD(pAC, IoC, ToPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		ClearAndStartRx(pAC, ToPort);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_RLMT_SEND:	 /* SK_MBUF *pMb */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("RLS "));
+		pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
+		pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
+		skb_put(pMsg, pRlmtMbuf->Length);
+		if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+			pMsg) < 0)
+
+			DEV_KFREE_SKB_ANY(pMsg);
+		break;
+	default:
+		break;
+	}
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+		("END EVENT "));
+
+	return (0);
+} /* SkDrvEvent */
+
+
+/*****************************************************************************
+ *
+ *	SkErrorLog - log errors
+ *
+ * Description:
+ *	This function logs errors to the system buffer and to the console
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *
+ */
+void SkErrorLog(
+SK_AC	*pAC,
+int	ErrClass,
+int	ErrNum,
+char	*pErrorMsg)
+{
+char	ClassStr[80];
+
+	switch (ErrClass) {
+	case SK_ERRCL_OTHER:
+		strcpy(ClassStr, "Other error");
+		break;
+	case SK_ERRCL_CONFIG:
+		strcpy(ClassStr, "Configuration error");
+		break;
+	case SK_ERRCL_INIT:
+		strcpy(ClassStr, "Initialization error");
+		break;
+	case SK_ERRCL_NORES:
+		strcpy(ClassStr, "Out of resources error");
+		break;
+	case SK_ERRCL_SW:
+		strcpy(ClassStr, "internal Software error");
+		break;
+	case SK_ERRCL_HW:
+		strcpy(ClassStr, "Hardware failure");
+		break;
+	case SK_ERRCL_COMM:
+		strcpy(ClassStr, "Communication error");
+		break;
+	}
+	printk(KERN_INFO "%s: -- ERROR --\n        Class:  %s\n"
+		"        Nr:  0x%x\n        Msg:  %s\n", pAC->dev[0]->name,
+		ClassStr, ErrNum, pErrorMsg);
+
+} /* SkErrorLog */
+
+#ifdef DEBUG
+/****************************************************************************/
+/* "debug only" section *****************************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	DumpMsg - print a frame
+ *
+ * Description:
+ *	This function prints frames to the system logfile/to the console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpMsg(struct sk_buff *skb, char *str)
+{
+	int	msglen;
+
+	if (skb == NULL) {
+		printk("DumpMsg(): NULL-Message\n");
+		return;
+	}
+
+	if (skb->data == NULL) {
+		printk("DumpMsg(): Message empty\n");
+		return;
+	}
+
+	msglen = skb->len;
+	if (msglen > 64)
+		msglen = 64;
+
+	printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+
+	DumpData((char *)skb->data, msglen);
+
+	printk("------- End of message ---------\n");
+} /* DumpMsg */
+
+
+/*****************************************************************************
+ *
+ *	DumpData - print a data area
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the
+ *	console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpData(char *p, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	for (i=0; i < size; ) {
+		if (*p >= '0' && *p <='z')
+			asc_buffer[addr] = *p;
+		else
+			asc_buffer[addr] = '.';
+		addr++;
+		asc_buffer[addr] = 0;
+		hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[*p & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%16 == 0) {
+			printk("%s  %s\n", hex_buffer, asc_buffer);
+			addr = 0;
+			haddr = 0;
+		}
+	}
+} /* DumpData */
+
+
+/*****************************************************************************
+ *
+ *	DumpLong - print a data area as long values
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the
+ *	console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpLong(char *pc, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+long	*p;
+int	l;
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	p = (long*) pc;
+	for (i=0; i < size; ) {
+		l = (long) *p;
+		hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[l & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%8 == 0) {
+			printk("%4x %s\n", (i-8)*4, hex_buffer);
+			haddr = 0;
+		}
+	}
+	printk("------------------------\n");
+} /* DumpLong */
+
+#endif
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skgehwt.c b/drivers/net/sk98lin/skgehwt.c
new file mode 100644
index 0000000..f8681a8
--- /dev/null
+++ b/drivers/net/sk98lin/skgehwt.c
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * Name:	skgehwt.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.13 $
+ * Date:	$Date: 1999/11/22 13:31:12 $
+ * Purpose:	Hardware Timer.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgehwt.c,v $
+ *	Revision 1.13  1999/11/22 13:31:12  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.12  1998/10/15 15:11:34  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *
+ *	Revision 1.11  1998/10/08 15:27:51  gklug
+ *	chg: correction factor is host clock dependent
+ *
+ *	Revision 1.10  1998/09/15 14:18:31  cgoos
+ *	Changed more BOOLEANs to SK_xxx
+ *
+ *	Revision 1.9  1998/09/15 14:16:06  cgoos
+ *	Changed line 107: FALSE to SK_FALSE
+ *
+ *	Revision 1.8  1998/08/24 13:04:44  gklug
+ *	fix: typo
+ *
+ *	Revision 1.7  1998/08/19 09:50:49  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.6  1998/08/17 09:59:02  gklug
+ *	fix: typos
+ *
+ *	Revision 1.5  1998/08/14 07:09:10  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.4  1998/08/10 14:14:52  gklug
+ *	rmv: unneccessary SK_ADDR macro
+ *
+ *	Revision 1.3  1998/08/07 12:53:44  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.2  1998/08/07 09:19:29  gklug
+ *	adapt functions to the C coding conventions
+ *	rmv unneccessary functions.
+ *
+ *	Revision 1.1  1998/08/05 11:28:36  gklug
+ *	first version: adapted from SMT/FDDI
+ *
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Hardware Timer function queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+#define	SK_HWT_MAX	(65000)
+
+/* correction factor */
+#define	SK_HWT_FAC	(1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100)
+
+/*
+ * Initialize hardware timer.
+ *
+ * Must be called during init level 1.
+ */
+void	SkHwtInit(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	pAC->Hwt.TStart = 0 ;
+	pAC->Hwt.TStop	= 0 ;
+	pAC->Hwt.TActive = SK_FALSE ;
+
+	SkHwtStop(pAC,Ioc) ;
+}
+
+/*
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ */
+void	SkHwtStart(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc,	/* IoContext */
+SK_U32	Time)	/* Time in units of 16us to load the timer with. */
+{
+	SK_U32	Cnt ;
+
+	if (Time > SK_HWT_MAX)
+		Time = SK_HWT_MAX ;
+
+	pAC->Hwt.TStart = Time ;
+	pAC->Hwt.TStop = 0L ;
+
+	Cnt = Time ;
+
+	/*
+	 * if time < 16 us
+	 *	time = 16 us
+	 */
+	if (!Cnt) {
+		Cnt++ ;
+	}
+
+	SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC) ;
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_START) ;	/* Start timer. */
+
+	pAC->Hwt.TActive = SK_TRUE ;
+}
+
+/*
+ * Stop hardware timer.
+ * and clear the timer IRQ
+ */
+void	SkHwtStop(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_STOP) ;
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_CLR_IRQ) ;
+
+	pAC->Hwt.TActive = SK_FALSE ;
+}
+
+
+/*
+ *	Stop hardware timer and read time elapsed since last start.
+ *
+ * returns
+ *	The elapsed time since last start in units of 16us.
+ *
+ */
+SK_U32	SkHwtRead(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_U32	TRead ;
+	SK_U32	IStatus ;
+
+	if (pAC->Hwt.TActive) {
+		SkHwtStop(pAC,Ioc) ;
+
+		SK_IN32(Ioc, B2_TI_VAL, &TRead);
+		TRead /= SK_HWT_FAC;
+
+		SK_IN32(Ioc, B0_ISRC, &IStatus);
+
+		/* Check if timer expired (or wraparound). */
+		if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) {
+			SkHwtStop(pAC,Ioc) ;
+			pAC->Hwt.TStop = pAC->Hwt.TStart ;
+		} else {
+			pAC->Hwt.TStop = pAC->Hwt.TStart - TRead ;
+		}
+	}
+	return (pAC->Hwt.TStop) ;
+}
+
+/*
+ * interrupt source= timer
+ */
+void	SkHwtIsr(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SkHwtStop(pAC,Ioc);
+	pAC->Hwt.TStop = pAC->Hwt.TStart;
+	SkTimerDone(pAC,Ioc) ;
+}
+
+#endif /* CONFIG_SK98 */
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c
new file mode 100644
index 0000000..a18dc0a
--- /dev/null
+++ b/drivers/net/sk98lin/skgeinit.c
@@ -0,0 +1,2372 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.85 $
+ * Date:	$Date: 2003/02/05 15:30:33 $
+ * Purpose:	Contains functions to initialize the GE HW
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgeinit.c,v $
+ *	Revision 1.85  2003/02/05 15:30:33  rschmidt
+ *	Corrected setting of GIHstClkFact (Host Clock Factor) and
+ *	GIPollTimerVal (Descr. Poll Timer Init Value) for YUKON.
+ *	Editorial changes.
+ *
+ *	Revision 1.84  2003/01/28 09:57:25  rschmidt
+ *	Added detection of YUKON-Lite Rev. A0 (stored in GIYukonLite).
+ *	Disabled Rx GMAC FIFO Flush for YUKON-Lite Rev. A0.
+ *	Added support for CLK_RUN (YUKON-Lite).
+ *	Added additional check of PME from D3cold for setting GIVauxAvail.
+ *	Editorial changes.
+ *
+ *	Revision 1.83  2002/12/17 16:15:41  rschmidt
+ *	Added default setting of PhyType (Copper) for YUKON.
+ *	Added define around check for HW self test results.
+ *	Editorial changes.
+ *
+ *	Revision 1.82  2002/12/05 13:40:21  rschmidt
+ *	Added setting of Rx GMAC FIFO Flush Mask register.
+ *	Corrected PhyType with new define SK_PHY_MARV_FIBER when
+ *	YUKON Fiber board was found.
+ *	Editorial changes.
+ *
+ *	Revision 1.81  2002/11/15 12:48:35  rschmidt
+ *	Replaced message SKERR_HWI_E018 with SKERR_HWI_E024 for Rx queue error
+ *	in SkGeStopPort().
+ *	Added init for pAC->GIni.GIGenesis with SK_FALSE in YUKON-branch.
+ *	Editorial changes.
+ *
+ *	Revision 1.80  2002/11/12 17:28:30  rschmidt
+ *	Initialized GIPciSlot64 and GIPciClock66 in SkGeInit1().
+ *	Reduced PCI FIFO watermarks for 32bit/33MHz bus in SkGeInitBmu().
+ *	Editorial changes.
+ *
+ *	Revision 1.79  2002/10/21 09:31:02  mkarl
+ *	Changed SkGeInitAssignRamToQueues(), removed call to
+ *	SkGeInitAssignRamToQueues in SkGeInit1 and fixed compiler warning in
+ *	SkGeInit1.
+ *
+ *	Revision 1.78  2002/10/16 15:55:07  mkarl
+ *	Fixed a bug in SkGeInitAssignRamToQueues.
+ *
+ *	Revision 1.77  2002/10/14 15:07:22  rschmidt
+ *	Corrected timeout handling for Rx queue in SkGeStopPort() (#10748)
+ *	Editorial changes.
+ *
+ *	Revision 1.76  2002/10/11 09:24:38  mkarl
+ *	Added check for HW self test results.
+ *
+ *	Revision 1.75  2002/10/09 16:56:44  mkarl
+ *	Now call SkGeInitAssignRamToQueues() in Init Level 1 in order to assign
+ *	the adapter memory to the queues. This default assignment is not suitable
+ *	for dual net mode.
+ *
+ *	Revision 1.74  2002/09/12 08:45:06  rwahl
+ *	Set defaults for PMSCap, PLinkSpeed & PLinkSpeedCap dependent on PHY.
+ *
+ *	Revision 1.73  2002/08/16 15:19:45  rschmidt
+ *	Corrected check for Tx queues in SkGeCheckQSize().
+ *	Added init for new entry GIGenesis and GICopperType
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
+ *
+ *	Revision 1.72  2002/08/12 13:38:55  rschmidt
+ *	Added check if VAUX is available (stored in GIVauxAvail)
+ *	Initialized PLinkSpeedCap in Port struct with SK_LSPEED_CAP_1000MBPS
+ *	Editorial changes.
+ *
+ *	Revision 1.71  2002/08/08 16:32:58  rschmidt
+ *	Added check for Tx queues in SkGeCheckQSize().
+ *	Added start of Time Stamp Timer (YUKON) in SkGeInit2().
+ *	Editorial changes.
+ *
+ *	Revision 1.70  2002/07/23 16:04:26  rschmidt
+ *	Added init for GIWolOffs (HW-Bug in YUKON 1st rev.)
+ *	Minor changes
+ *
+ *	Revision 1.69  2002/07/17 17:07:08  rwahl
+ *	- SkGeInit1(): fixed PHY type debug output; corrected init of GIFunc
+ *	  table & GIMacType.
+ *	- Editorial changes.
+ *
+ *	Revision 1.68  2002/07/15 18:38:31  rwahl
+ *	Added initialization for MAC type dependent function table.
+ *
+ *	Revision 1.67  2002/07/15 15:45:39  rschmidt
+ *	Added Tx Store & Forward for YUKON (GMAC Tx FIFO is only 1 kB)
+ *	Replaced SK_PHY_MARV by SK_PHY_MARV_COPPER
+ *	Editorial changes
+ *
+ *	Revision 1.66  2002/06/10 09:35:08  rschmidt
+ *	Replaced C++ comments (//)
+ *	Editorial changes
+ *
+ *	Revision 1.65  2002/06/05 08:33:37  rschmidt
+ *	Changed GIRamSize and Reset sequence for YUKON.
+ *	SkMacInit() replaced by SkXmInitMac() resp. SkGmInitMac()
+ *
+ *	Revision 1.64  2002/04/25 13:03:20  rschmidt
+ *	Changes for handling YUKON.
+ *	Removed reference to xmac_ii.h (not necessary).
+ *	Moved all defines into header file.
+ *	Replaced all SkXm...() functions with SkMac...() to handle also
+ *	YUKON's GMAC.
+ *	Added handling for GMAC FIFO in SkGeInitMacFifo(), SkGeStopPort().
+ *	Removed 'goto'-directive from SkGeCfgSync(), SkGeCheckQSize().
+ *	Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
+ *	SkMacFlushTxFifo().
+ *	Optimized timeout handling in SkGeStopPort().
+ *	Initialized PLinkSpeed in Port struct with SK_LSPEED_AUTO.
+ *	Release of GMAC Link Control reset in SkGeInit1().
+ *	Initialized GIChipId and GIChipRev in GE Init structure.
+ *	Added GIRamSize and PhyType values for YUKON.
+ *	Removed use of PRxCmd to setup XMAC.
+ *	Moved setting of XM_RX_DIS_CEXT to SkXmInitMac().
+ *	Use of SkGeXmitLED() only for GENESIS.
+ *	Changes for V-CPU support.
+ *	Editorial changes.
+ *
+ *	Revision 1.63  2001/04/05 11:02:09  rassmann
+ *	Stop Port check of the STOP bit did not take 2/18 sec as wanted.
+ *
+ *	Revision 1.62  2001/02/07 07:54:21  rassmann
+ *	Corrected copyright.
+ *
+ *	Revision 1.61  2001/01/31 15:31:40  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *
+ *	Revision 1.60  2000/10/18 12:22:21  cgoos
+ *	Added workaround for half duplex hangup.
+ *
+ *	Revision 1.59  2000/10/10 11:22:06  gklug
+ *	add: in manual half duplex mode ignore carrier extension errors
+ *
+ *	Revision 1.58  2000/10/02 14:10:27  rassmann
+ *	Reading BCOM PHY after releasing reset until it returns a valid value.
+ *
+ *	Revision 1.57  2000/08/03 14:55:28  rassmann
+ *	Waiting for I2C to be ready before de-initializing adapter
+ *	(prevents sensors from hanging up).
+ *
+ *	Revision 1.56  2000/07/27 12:16:48  gklug
+ *	fix: Stop Port check of the STOP bit does now take 2/18 sec as wanted
+ *
+ *	Revision 1.55  1999/11/22 13:32:26  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.54  1999/10/26 07:32:54  malthoff
+ *	Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics.
+ *
+ *	Revision 1.53  1999/08/12 19:13:50  malthoff
+ *	Fix for 1000BT. Do not owerwrite XM_MMU_CMD when
+ *	disabling receiver and transmitter. Other bits
+ *	may be lost.
+ *
+ *	Revision 1.52  1999/07/01 09:29:54  gklug
+ *	fix: DoInitRamQueue needs pAC
+ *
+ *	Revision 1.51  1999/07/01 08:42:21  gklug
+ *	chg: use Store & forward for RAM buffer when Jumbos are used
+ *
+ *	Revision 1.50  1999/05/27 13:19:38  cgoos
+ *	Added Tx PCI watermark initialization.
+ *	Removed Tx RAM queue Store & Forward setting.
+ *
+ *	Revision 1.49  1999/05/20 14:32:45  malthoff
+ *	SkGeLinkLED() is completly removed now.
+ *
+ *	Revision 1.48  1999/05/19 07:28:24  cgoos
+ *	SkGeLinkLED no more available for drivers.
+ *	Changes for 1000Base-T.
+ *
+ *	Revision 1.47  1999/04/08 13:57:45  gklug
+ *	add: Init of new port struct fiels PLinkResCt
+ *	chg: StopPort Timer check
+ *
+ *	Revision 1.46  1999/03/25 07:42:15  malthoff
+ *	SkGeStopPort(): Add workaround for cache incoherency.
+ *			Create error log entry, disable port, and
+ *			exit loop if it does not terminate.
+ *	Add XM_RX_LENERR_OK to the default value for the
+ *	XMAC receive command register.
+ *
+ *	Revision 1.45  1999/03/12 16:24:47  malthoff
+ *	Remove PPollRxD and PPollTxD.
+ *	Add check for GIPollTimerVal.
+ *
+ *	Revision 1.44  1999/03/12 13:40:23  malthoff
+ *	Fix: SkGeXmitLED(), SK_LED_TST mode does not work.
+ *	Add: Jumbo frame support.
+ *	Chg: Resolution of parameter IntTime in SkGeCfgSync().
+ *
+ *	Revision 1.43  1999/02/09 10:29:46  malthoff
+ *	Bugfix: The previous modification again also for the second location.
+ *
+ *	Revision 1.42  1999/02/09 09:35:16  malthoff
+ *	Bugfix: The bits '66 MHz Capable' and 'NEWCAP are reset while
+ *		clearing the error bits in the PCI status register.
+ *
+ *	Revision 1.41  1999/01/18 13:07:02  malthoff
+ *	Bugfix: Do not use CFG cycles after during Init- or Runtime, because
+ *		they may not be available after Boottime.
+ *
+ *	Revision 1.40  1999/01/11 12:40:49  malthoff
+ *	Bug fix: PCI_STATUS: clearing error bits sets the UDF bit.
+ *
+ *	Revision 1.39  1998/12/11 15:17:33  gklug
+ *	chg: Init LipaAutoNeg with Unknown
+ *
+ *	Revision 1.38  1998/12/10 11:02:57  malthoff
+ *	Disable Error Log Message when calling SkGeInit(level 2)
+ *	more than once.
+ *
+ *	Revision 1.37  1998/12/07 12:18:25  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *
+ *	Revision 1.36  1998/12/07 07:10:39  gklug
+ *	fix: init values of LinkBroken/ Capabilities for management
+ *
+ *	Revision 1.35  1998/12/02 10:56:20  gklug
+ *	fix: do NOT init LoinkSync Counter.
+ *
+ *	Revision 1.34  1998/12/01 10:53:21  gklug
+ *	add: init of additional Counters for workaround
+ *
+ *	Revision 1.33  1998/12/01 10:00:49  gklug
+ *	add: init PIsave var in Port struct
+ *
+ *	Revision 1.32  1998/11/26 14:50:40  gklug
+ *	chg: Default is autosensing with AUTOFULL mode
+ *
+ *	Revision 1.31  1998/11/25 15:36:16  gklug
+ *	fix: do NOT stop LED Timer when port should be stopped
+ *
+ *	Revision 1.30  1998/11/24 13:15:28  gklug
+ *	add: Init PCkeckPar struct member
+ *
+ *	Revision 1.29  1998/11/18 13:19:27  malthoff
+ *	Disable packet arbiter timeouts on receive side.
+ *	Use maximum timeout value for packet arbiter
+ *	transmit timeouts.
+ *	Add TestStopBit() function to handle stop RX/TX
+ *	problem with active descriptor poll timers.
+ *	Bug Fix: Descriptor Poll Timer not started, because
+ *	GIPollTimerVal was initialized with 0.
+ *
+ *	Revision 1.28  1998/11/13 14:24:26  malthoff
+ *	Bug Fix: SkGeStopPort() may hang if a Packet Arbiter Timout
+ *	is pending or occurs while waiting for TX_STOP and RX_STOP.
+ *	The PA timeout is cleared now while waiting for TX- or RX_STOP.
+ *
+ *	Revision 1.27  1998/11/02 11:04:36  malthoff
+ *	fix the last fix
+ *
+ *	Revision 1.26  1998/11/02 10:37:03  malthoff
+ *	Fix: SkGePollTxD() enables always the synchronounous poll timer.
+ *
+ *	Revision 1.25  1998/10/28 07:12:43  cgoos
+ *	Fixed "LED_STOP" in SkGeLnkSyncCnt, "== SK_INIT_IO" in SkGeInit.
+ *	Removed: Reset of RAM Interface in SkGeStopPort.
+ *
+ *	Revision 1.24  1998/10/27 08:13:12  malthoff
+ *	Remove temporary code.
+ *
+ *	Revision 1.23  1998/10/26 07:45:03  malthoff
+ *	Add Address Calculation Workaround: If the EPROM byte
+ *	Id is 3, the address offset is 512 kB.
+ *	Initialize default values for PLinkMode and PFlowCtrlMode.
+ *
+ *	Revision 1.22  1998/10/22 09:46:47  gklug
+ *	fix SysKonnectFileId typo
+ *
+ *	Revision 1.21  1998/10/20 12:11:56  malthoff
+ *	Don't dendy the Queue config if the size of the unused
+ *	Rx qeueu is zero.
+ *
+ *	Revision 1.20  1998/10/19 07:27:58  malthoff
+ *	SkGeInitRamIface() is public to be called by diagnostics.
+ *
+ *	Revision 1.19  1998/10/16 13:33:45  malthoff
+ *	Fix: enabling descriptor polling is not allowed until
+ *	the descriptor addresses are set. Descriptor polling
+ *	must be handled by the driver.
+ *
+ *	Revision 1.18  1998/10/16 10:58:27  malthoff
+ *	Remove temp. code for Diag prototype.
+ *	Remove lint warning for dummy reads.
+ *	Call SkGeLoadLnkSyncCnt() during SkGeInitPort().
+ *
+ *	Revision 1.17  1998/10/14 09:16:06  malthoff
+ *	Change parameter LimCount and programming of
+ *	the limit counter in SkGeCfgSync().
+ *
+ *	Revision 1.16  1998/10/13 09:21:16  malthoff
+ *	Don't set XM_RX_SELF_RX in RxCmd Reg, because it's
+ *	like a Loopback Mode in half duplex.
+ *
+ *	Revision 1.15  1998/10/09 06:47:40  malthoff
+ *	SkGeInitMacArb(): set recovery counters init value
+ *	to zero although this counters are not uesd.
+ *	Bug fix in Rx Upper/Lower Pause Threshold calculation.
+ *	Add XM_RX_SELF_RX to RxCmd.
+ *
+ *	Revision 1.14  1998/10/06 15:15:53  malthoff
+ *	Make sure no pending IRQ is cleared in SkGeLoadLnkSyncCnt().
+ *
+ *	Revision 1.13  1998/10/06 14:09:36  malthoff
+ *	Add SkGeLoadLnkSyncCnt(). Modify
+ *	the 'port stopped' condition according
+ *	to the current problem report.
+ *
+ *	Revision 1.12  1998/10/05 08:17:21  malthoff
+ *	Add functions: SkGePollRxD(), SkGePollTxD(),
+ *	DoCalcAddr(), SkGeCheckQSize(),
+ *	DoInitRamQueue(), and SkGeCfgSync().
+ *	Add coding for SkGeInitMacArb(), SkGeInitPktArb(),
+ *	SkGeInitMacFifo(), SkGeInitRamBufs(),
+ *	SkGeInitRamIface(), and SkGeInitBmu().
+ *
+ *	Revision 1.11  1998/09/29 08:26:29  malthoff
+ *	bug fix: SkGeInit0() 'i' should be increment.
+ *
+ *	Revision 1.10  1998/09/28 13:19:01  malthoff
+ *	Coding time: Save the done work.
+ *	Modify SkGeLinkLED(), add SkGeXmitLED(),
+ *	define SkGeCheckQSize(), SkGeInitMacArb(),
+ *	SkGeInitPktArb(), SkGeInitMacFifo(),
+ *	SkGeInitRamBufs(), SkGeInitRamIface(),
+ *	and SkGeInitBmu(). Do coding for SkGeStopPort(),
+ *	SkGeInit1(), SkGeInit2(), and SkGeInit3().
+ *	Do coding for SkGeDinit() and SkGeInitPort().
+ *
+ *	Revision 1.9  1998/09/16 14:29:05  malthoff
+ *	Some minor changes.
+ *
+ *	Revision 1.8  1998/09/11 05:29:14  gklug
+ *	add: init state of a port
+ *
+ *	Revision 1.7  1998/09/04 09:26:25  malthoff
+ *	Short temporary modification.
+ *
+ *	Revision 1.6  1998/09/04 08:27:59  malthoff
+ *	Remark the do-while in StopPort() because it never ends
+ *	without a GE adapter.
+ *
+ *	Revision 1.5  1998/09/03 14:05:45  malthoff
+ *	Change comment for SkGeInitPort(). Do not
+ *	repair the queue sizes if invalid.
+ *
+ *	Revision 1.4  1998/09/03 10:03:19  malthoff
+ *	Implement the new interface according to the
+ *	reviewed interface specification.
+ *
+ *	Revision 1.3  1998/08/19 09:11:25  gklug
+ *	fix: struct are removed from c-source (see CCC)
+ *
+ *	Revision 1.2  1998/07/28 12:33:58  malthoff
+ *	Add 'IoC' parameter in function declaration and SK IO macros.
+ *
+ *	Revision 1.1  1998/07/23 09:48:57  malthoff
+ *	Creation. First dummy 'C' file.
+ *	SkGeInit(Level 0) is card_start for GE.
+ *	SkGeDeInit() is card_stop for GE.
+ *
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skgeinit.c,v 1.85 2003/02/05 15:30:33 rschmidt Exp $ (C) SK ";
+
+struct s_QOffTab {
+	int	RxQOff;		/* Receive Queue Address Offset */
+	int	XsQOff;		/* Sync Tx Queue Address Offset */
+	int	XaQOff;		/* Async Tx Queue Address Offset */
+};
+static struct s_QOffTab QOffTab[] = {
+	{Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
+};
+
+
+/******************************************************************************
+ *
+ *	SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring
+ *
+ * Description:
+ *	Enable or disable the descriptor polling of the receive descriptor
+ *	ring (RxD) for port 'Port'.
+ *	The new configuration is *not* saved over any SkGeStopPort() and
+ *	SkGeInitPort() calls.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePollRxD(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL PollRxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (PollRxD) ?
+		CSR_ENA_POL : CSR_DIS_POL);
+}	/* SkGePollRxD */
+
+
+/******************************************************************************
+ *
+ *	SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
+ *
+ * Description:
+ *	Enable or disable the descriptor polling of the transmit descriptor
+ *	ring(s) (TxD) for port 'Port'.
+ *	The new configuration is *not* saved over any SkGeStopPort() and
+ *	SkGeInitPort() calls.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePollTxD(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL PollTxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	DWord = (PollTxD) ? CSR_ENA_POL : CSR_DIS_POL;
+
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
+	}
+
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
+	}
+}	/* SkGePollTxD */
+
+
+/******************************************************************************
+ *
+ *	SkGeYellowLED() - Switch the yellow LED on or off.
+ *
+ * Description:
+ *	Switch the yellow LED on or off.
+ *
+ * Note:
+ *	This function may be called any time after SkGeInit(Level 1).
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeYellowLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		State)		/* yellow LED state, 0 = OFF, 0 != ON */
+{
+	if (State == 0) {
+		/* Switch yellow LED OFF */
+		SK_OUT8(IoC, B0_LED, LED_STAT_OFF);
+	}
+	else {
+		/* Switch yellow LED ON */
+		SK_OUT8(IoC, B0_LED, LED_STAT_ON);
+	}
+}	/* SkGeYellowLED */
+
+
+/******************************************************************************
+ *
+ *	SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
+ *
+ * Description:
+ *	The Rx or Tx LED which is specified by 'Led' will be
+ *	enabled, disabled or switched on in test mode.
+ *
+ * Note:
+ *	'Led' must contain the address offset of the LEDs INI register.
+ *
+ * Usage:
+ *	SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeXmitLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Led,		/* offset to the LED Init Value register */
+int		Mode)		/* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
+{
+	SK_U32	LedIni;
+
+	switch (Mode) {
+	case SK_LED_ENA:
+		LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+		SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
+		SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+		break;
+	case SK_LED_TST:
+		SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
+		SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
+		SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+		break;
+	case SK_LED_DIS:
+	default:
+		/*
+		 * Do NOT stop the LED Timer here. The LED might be
+		 * in on state. But it needs to go off.
+		 */
+		SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
+		SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
+		break;
+	}
+
+	/*
+	 * 1000BT: The Transmit LED is driven by the PHY.
+	 * But the default LED configuration is used for
+	 * Level One and Broadcom PHYs.
+	 * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
+	 * (In this case it has to be added here. But we will see. XXX)
+	 */
+}	/* SkGeXmitLED */
+
+
+/******************************************************************************
+ *
+ *	DoCalcAddr() - Calculates the start and the end address of a queue.
+ *
+ * Description:
+ *	This function calculates the start and the end address of a queue.
+ *  Afterwards the 'StartVal' is incremented to the next start position.
+ *	If the port is already initialized the calculated values
+ *	will be checked against the configured values and an
+ *	error will be returned, if they are not equal.
+ *	If the port is not initialized the values will be written to
+ *	*StartAdr and *EndAddr.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	configuration error
+ */
+static int DoCalcAddr(
+SK_AC		*pAC, 			/* adapter context */
+SK_GEPORT	*pPrt,			/* port index */
+int			QuSize,			/* size of the queue to configure in kB */
+SK_U32		*StartVal,		/* start value for address calculation */
+SK_U32		*QuStartAddr,	/* start addr to calculate */
+SK_U32		*QuEndAddr)		/* end address to calculate */
+{
+	SK_U32	EndVal;
+	SK_U32	NextStart;
+	int		Rtv;
+
+	Rtv = 0;
+	if (QuSize == 0) {
+		EndVal = *StartVal;
+		NextStart = EndVal;
+	}
+	else {
+		EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
+		NextStart = EndVal + 1;
+	}
+
+	if (pPrt->PState >= SK_PRT_INIT) {
+		if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
+			Rtv = 1;
+		}
+	}
+	else {
+		*QuStartAddr = *StartVal;
+		*QuEndAddr = EndVal;
+	}
+
+	*StartVal = NextStart;
+	return(Rtv);
+}	/* DoCalcAddr */
+
+/******************************************************************************
+ *
+ *	SkGeInitAssignRamToQueues() - allocate default queue sizes
+ *
+ * Description:
+ *	This function assigns the memory to the different queues and ports.
+ *	When DualNet is set to SK_TRUE all ports get the same amount of memory.
+ *  Otherwise the first port gets most of the memory and all the
+ *	other ports just the required minimum.
+ *	This function can only be called when pAC->GIni.GIRamSize and
+ *	pAC->GIni.GIMacsFound have been initialized, usually this happens
+ *	at init level 1
+ *
+ * Returns:
+ *	0 - ok
+ *	1 - invalid input values
+ *	2 - not enough memory
+ */
+
+int SkGeInitAssignRamToQueues(
+SK_AC	*pAC,			/* Adapter context */
+int		ActivePort,		/* Active Port in RLMT mode */
+SK_BOOL	DualNet)		/* adapter context */
+{
+	int	i;
+	int	UsedKilobytes;			/* memory already assigned */
+	int	ActivePortKilobytes;	/* memory available for active port */
+	SK_GEPORT *pGePort;
+
+	UsedKilobytes = 0;
+
+	if (ActivePort >= pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
+			ActivePort));
+		return(1);
+	}
+	if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
+		((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
+			 pAC->GIni.GIRamSize));
+		return(2);
+	}
+
+
+	if (DualNet) {
+		/* every port gets the same amount of memory */
+		ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			pGePort = &pAC->GIni.GP[i];
+
+			/* take away the minimum memory for active queues */
+			ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+
+			/* receive queue gets the minimum + 80% of the rest */
+			pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
+				ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
+				+ SK_MIN_RXQ_SIZE;
+
+			ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+			/* synchronous transmit queue */
+			pGePort->PXSQSize = 0;
+
+			/* asynchronous transmit queue */
+			pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
+				SK_MIN_TXQ_SIZE);
+		}
+	}
+	else {
+		/* Rlmt Mode or single link adapter */
+
+		/* Set standby queue size defaults for all standby ports */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			if (i != ActivePort) {
+				pGePort = &pAC->GIni.GP[i];
+
+				pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
+				pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
+				pGePort->PXSQSize = 0;
+
+				/* Count used RAM */
+				UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
+			}
+		}
+		/* what's left? */
+		ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;
+
+		/* assign it to the active port */
+		/* first take away the minimum memory */
+		ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+		pGePort = &pAC->GIni.GP[ActivePort];
+
+		/* receive queue get's the minimum + 80% of the rest */
+		pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
+			(unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;
+
+		ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+		/* synchronous transmit queue */
+		pGePort->PXSQSize = 0;
+
+		/* asynchronous transmit queue */
+		pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
+			SK_MIN_TXQ_SIZE;
+	}
+#ifdef VCPU
+	VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
+		pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
+#endif /* VCPU */
+
+	return(0);
+}	/* SkGeInitAssignRamToQueues */
+
+/******************************************************************************
+ *
+ *	SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
+ *
+ * Description:
+ *	This function verifies the Queue Size Configuration specified
+ *	in the variables PRxQSize, PXSQSize, and PXAQSize of all
+ *	used ports.
+ *	This requirements must be fullfilled to have a valid configuration:
+ *		- The size of all queues must not exceed GIRamSize.
+ *		- The queue sizes must be specified in units of 8 kB.
+ *		- The size of Rx queues of available ports must not be
+ *		  smaller than 16 kB.
+ *		- The size of at least one Tx queue (synch. or asynch.)
+ *        of available ports must not be smaller than 16 kB
+ *        when Jumbo Frames are used.
+ *		- The RAM start and end addresses must not be changed
+ *		  for ports which are already initialized.
+ *	Furthermore SkGeCheckQSize() defines the Start and End Addresses
+ *  of all ports and stores them into the HWAC port	structure.
+ *
+ * Returns:
+ *	0:	Queue Size Configuration valid
+ *	1:	Queue Size Configuration invalid
+ */
+static int SkGeCheckQSize(
+SK_AC	 *pAC,		/* adapter context */
+int		 Port)		/* port index */
+{
+	SK_GEPORT *pPrt;
+	int	UsedMem;	/* total memory used (max. found ports) */
+	int	i;
+	int	Rtv;
+	int	Rtv2;
+	SK_U32	StartAddr;
+
+	UsedMem = 0;
+	Rtv = 0;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXSQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXAQSize & QZ_UNITS) != 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+			return(1);
+		}
+
+		if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
+			return(1);
+		}
+
+		/*
+		 * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
+		 * if Jumbo Frames are used, this size has to be >= 16 kB.
+		 */
+		if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
+			(pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
+	    ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
+			 (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
+				return(1);
+		}
+
+		UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
+	}
+
+	if (UsedMem > pAC->GIni.GIRamSize) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+		return(1);
+	}
+
+	/* Now start address calculation */
+	StartAddr = pAC->GIni.GIRamOffs;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		/* Calculate/Check values for the receive queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
+			&pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the synchronous Tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
+			&pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the asynchronous Tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
+			&pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
+		Rtv |= Rtv2;
+
+		if (Rtv) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
+			return(1);
+		}
+	}
+
+	return(0);
+}	/* SkGeCheckQSize */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitMacArb() - Initialize the MAC Arbiter
+ *
+ * Description:
+ *	This function initializes the MAC Arbiter.
+ *	It must not be called if there is still an
+ *	initialized or active port.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitMacArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+	SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
+
+	/* recovery values are needed for XMAC II Rev. B2 only */
+	/* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
+
+	/*
+	 * There is no start or enable button to push, therefore
+	 * the MAC arbiter is configured and enabled now.
+	 */
+}	/* SkGeInitMacArb */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitPktArb() - Initialize the Packet Arbiter
+ *
+ * Description:
+ *	This function initializes the Packet Arbiter.
+ *	It must not be called if there is still an
+ *	initialized or active port.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitPktArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+
+	/*
+	 * enable timeout timers if jumbo frames not used
+	 * NOTE: the packet arbiter timeout interrupt is needed for
+	 * half duplex hangup workaround
+	 */
+	if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
+		if (pAC->GIni.GIMacsFound == 1) {
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
+		}
+		else {
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
+		}
+	}
+}	/* SkGeInitPktArb */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitMacFifo() - Initialize the MAC FIFOs
+ *
+ * Description:
+ *	Initialize all MAC FIFOs of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitMacFifo(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Word;
+#ifdef VCPU
+	SK_U32	DWord;
+#endif /* VCPU */
+	/*
+	 * For each FIFO:
+	 *	- release local reset
+	 *	- use default value for MAC FIFO size
+	 *	- setup defaults for the control register
+	 *	- enable the FIFO
+	 */
+
+	Word = GMF_RX_CTRL_DEF;
+
+	if (pAC->GIni.GIGenesis) {
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+		/* Enable frame flushing if jumbo frames used */
+		if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+			SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+		}
+	}
+	else {
+		/* set Rx GMAC FIFO Flush Mask */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
+
+		if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+
+			Word &= ~GMF_RX_F_FL_ON;
+		}
+
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);
+
+		/* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);
+
+#ifdef VCPU
+		SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
+		SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
+#endif /* VCPU */
+
+		/* set Tx GMAC FIFO Almost Empty Threshold */
+/*		SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
+	}
+}	/* SkGeInitMacFifo */
+
+
+/******************************************************************************
+ *
+ *	SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
+ *
+ * Description:
+ *	This function starts the Link Sync Counter of the specified
+ *	port and enables the generation of an Link Sync IRQ.
+ *	The Link Sync Counter may be used to detect an active link,
+ *	if autonegotiation is not used.
+ *
+ * Note:
+ *	o To ensure receiving the Link Sync Event the LinkSyncCounter
+ *	  should be initialized BEFORE clearing the XMAC's reset!
+ *	o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
+ *	  function.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeLoadLnkSyncCnt(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U32	CntVal)		/* Counter value */
+{
+	SK_U32	OrgIMsk;
+	SK_U32	NewIMsk;
+	SK_U32	ISrc;
+	SK_BOOL	IrqPend;
+
+	/* stop counter */
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP);
+
+	/*
+	 * ASIC problem:
+	 * Each time starting the Link Sync Counter an IRQ is generated
+	 * by the adapter. See problem report entry from 21.07.98
+	 *
+	 * Workaround:	Disable Link Sync IRQ and clear the unexpeced IRQ
+	 *		if no IRQ is already pending.
+	 */
+	IrqPend = SK_FALSE;
+	SK_IN32(IoC, B0_ISRC, &ISrc);
+	SK_IN32(IoC, B0_IMSK, &OrgIMsk);
+	if (Port == MAC_1) {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
+		if ((ISrc & IS_LNK_SYNC_M1) != 0) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	else {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
+		if ((ISrc & IS_LNK_SYNC_M2) != 0) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	if (!IrqPend) {
+		SK_OUT32(IoC, B0_IMSK, NewIMsk);
+	}
+
+	/* load counter */
+	SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);
+
+	/* start counter */
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START);
+
+	if (!IrqPend) {
+		/* clear the unexpected IRQ, and restore the interrupt mask */
+		SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ);
+		SK_OUT32(IoC, B0_IMSK, OrgIMsk);
+	}
+}	/* SkGeLoadLnkSyncCnt*/
+
+
+/******************************************************************************
+ *
+ *	SkGeCfgSync() - Configure synchronous bandwidth for this port.
+ *
+ * Description:
+ *	This function may be used to configure synchronous bandwidth
+ *	to the specified port. This may be done any time after
+ *	initializing the port. The configuration values are NOT saved
+ *	in the HWAC port structure and will be overwritten any
+ *	time when stopping and starting the port.
+ *	Any values for the synchronous configuration will be ignored
+ *	if the size of the synchronous queue is zero!
+ *
+ *	The default configuration for the synchronous service is
+ *	TXA_ENA_FSYNC. This means if the size of
+ *	the synchronous queue is unequal zero but no specific
+ *	synchronous bandwidth is configured, the synchronous queue
+ *	will always have the 'unlimited' transmit priority!
+ *
+ *	This mode will be restored if the synchronous bandwidth is
+ *	deallocated ('IntTime' = 0 and 'LimCount' = 0).
+ *
+ * Returns:
+ *	0:	success
+ *	1:	parameter configuration error
+ *	2:	try to configure quality of service although no
+ *		synchronous queue is configured
+ */
+int SkGeCfgSync(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U32	IntTime,	/* Interval Timer Value in units of 8ns */
+SK_U32	LimCount,	/* Number of bytes to transfer during IntTime */
+int		SyncMode)	/* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
+{
+	int Rtv;
+
+	Rtv = 0;
+
+	/* check the parameters */
+	if (LimCount > IntTime ||
+		(LimCount == 0 && IntTime != 0) ||
+		(LimCount != 0 && IntTime == 0)) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		return(1);
+	}
+
+	if (pAC->GIni.GP[Port].PXSQSize == 0) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
+		return(2);
+	}
+
+	/* calculate register values */
+	IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+	LimCount = LimCount / 8;
+
+	if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		return(1);
+	}
+
+	/*
+	 * - Enable 'Force Sync' to ensure the synchronous queue
+	 *   has the priority while configuring the new values.
+	 * - Also 'disable alloc' to ensure the settings complies
+	 *   to the SyncMode parameter.
+	 * - Disable 'Rate Control' to configure the new values.
+	 * - write IntTime and LimCount
+	 * - start 'Rate Control' and disable 'Force Sync'
+	 *   if Interval Timer or Limit Counter not zero.
+	 */
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
+
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		(SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
+
+	if (IntTime != 0 || LimCount != 0) {
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
+	}
+
+	return(0);
+}	/* SkGeCfgSync */
+
+
+/******************************************************************************
+ *
+ *	DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
+ *
+ * Desccription:
+ *	If the queue is used, enable and initialize it.
+ *	Make sure the queue is still reset, if it is not used.
+ *
+ * Returns:
+ *	nothing
+ */
+static void DoInitRamQueue(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* IO context */
+int		QuIoOffs,		/* Queue IO Address Offset */
+SK_U32	QuStartAddr,	/* Queue Start Address */
+SK_U32	QuEndAddr,		/* Queue End Address */
+int		QuType)			/* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
+{
+	SK_U32	RxUpThresVal;
+	SK_U32	RxLoThresVal;
+
+	if (QuStartAddr != QuEndAddr) {
+		/* calculate thresholds, assume we have a big Rx queue */
+		RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
+		RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
+
+		/* build HW address format */
+		QuStartAddr = QuStartAddr / 8;
+		QuEndAddr = QuEndAddr / 8;
+
+		/* release local reset */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);
+
+		/* configure addresses */
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);
+
+		switch (QuType) {
+		case SK_RX_SRAM_Q:
+			/* configure threshold for small Rx Queue */
+			RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
+
+			/* continue with SK_RX_BRAM_Q */
+		case SK_RX_BRAM_Q:
+			/* write threshold for Rx Queue */
+
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
+
+			/* the high priority threshold not used */
+			break;
+		case SK_TX_RAM_Q:
+			/*
+			 * Do NOT use Store & Forward under normal operation due to
+			 * performance optimization (GENESIS only).
+			 * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
+			 * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
+			 * we NEED Store & Forward of the RAM buffer.
+			 */
+			if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
+				!pAC->GIni.GIGenesis) {
+				/* enable Store & Forward Mode for the Tx Side */
+				SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
+			}
+			break;
+		}
+
+		/* set queue operational */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
+	}
+	else {
+		/* ensure the queue is still disabled */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
+	}
+}	/* DoInitRamQueue */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitRamBufs() - Initialize the RAM Buffer Queues
+ *
+ * Description:
+ *	Initialize all RAM Buffer Queues of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitRamBufs(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+	int RxQType;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
+		RxQType = SK_RX_SRAM_Q; 	/* small Rx Queue */
+	}
+	else {
+		RxQType = SK_RX_BRAM_Q;		/* big Rx Queue */
+	}
+
+	DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
+		pPrt->PRxQRamEnd, RxQType);
+
+	DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
+		pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+
+	DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
+		pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+
+}	/* SkGeInitRamBufs */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitRamIface() - Initialize the RAM Interface
+ *
+ * Description:
+ *	This function initializes the Adapters RAM Interface.
+ *
+ * Note:
+ *	This function is used in the diagnostics.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeInitRamIface(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+}	/* SkGeInitRamIface */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitBmu() - Initialize the BMU state machines
+ *
+ * Description:
+ *	Initialize all BMU state machines of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitBmu(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U32		RxWm;
+	SK_U32		TxWm;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	RxWm = SK_BMU_RX_WM;
+	TxWm = SK_BMU_TX_WM;
+
+	if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
+		/* for better performance */
+		RxWm /= 2;
+		TxWm /= 2;
+	}
+
+	/* Rx Queue: Release all local resets and set the watermark */
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
+
+	/*
+	 * Tx Queue: Release all local resets if the queue is used !
+	 * 		set watermark
+	 */
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
+	}
+
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
+	}
+	/*
+	 * Do NOT enable the descriptor poll timers here, because
+	 * the descriptor addresses are not specified yet.
+	 */
+}	/* SkGeInitBmu */
+
+
+/******************************************************************************
+ *
+ *	TestStopBit() -	Test the stop bit of the queue
+ *
+ * Description:
+ *	Stopping a queue is not as simple as it seems to be.
+ *	If descriptor polling is enabled, it may happen
+ *	that RX/TX stop is done and SV idle is NOT set.
+ *	In this case we have to issue another stop command.
+ *
+ * Returns:
+ *	The queues control status register
+ */
+static SK_U32 TestStopBit(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		QuIoOffs)	/* Queue IO Address Offset */
+{
+	SK_U32	QuCsr;	/* CSR contents */
+
+	SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+
+	if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
+		/* Stop Descriptor overridden by start command */
+		SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
+
+		SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+	}
+
+	return(QuCsr);
+}	/* TestStopBit */
+
+
+/******************************************************************************
+ *
+ *	SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
+ *
+ * Description:
+ *	After calling this function the descriptor rings and Rx and Tx
+ *	queues of this port may be reconfigured.
+ *
+ *	It is possible to stop the receive and transmit path separate or
+ *	both together.
+ *
+ *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets the MAC.
+ *				The receive queue is still active and
+ *				the pending Rx frames may be still transferred
+ *				into the RxD.
+ *		SK_STOP_RX	Stop the receive path. The tansmit path
+ *				has to be stopped once before.
+ *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
+ *
+ *	RstMode = SK_SOFT_RST	Resets the MAC. The PHY is still alive.
+ *			SK_HARD_RST	Resets the MAC and the PHY.
+ *
+ * Example:
+ *	1) A Link Down event was signaled for a port. Therefore the activity
+ *	of this port should be stopped and a hardware reset should be issued
+ *	to enable the workaround of XMAC errata #2. But the received frames
+ *	should not be discarded.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
+ *		(transfer all pending Rx frames)
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
+ *		...
+ *
+ *	2) An event was issued which request the driver to switch
+ *	the 'virtual active' link to an other already active port
+ *	as soon as possible. The frames in the receive queue of this
+ *	port may be lost. But the PHY must not be reset during this
+ *	event.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
+ *		...
+ *
+ * Extended Description:
+ *	If SK_STOP_TX is set,
+ *		o disable the MAC's receive and transmitter to prevent
+ *		  from sending incomplete frames
+ *		o stop the port's transmit queues before terminating the
+ *		  BMUs to prevent from performing incomplete PCI cycles
+ *		  on the PCI bus
+ *		- The network Rx and Tx activity and PCI Tx transfer is
+ *		  disabled now.
+ *		o reset the MAC depending on the RstMode
+ *		o Stop Interval Timer and Limit Counter of Tx Arbiter,
+ *		  also disable Force Sync bit and Enable Alloc bit.
+ *		o perform a local reset of the port's Tx path
+ *			- reset the PCI FIFO of the async Tx queue
+ *			- reset the PCI FIFO of the sync Tx queue
+ *			- reset the RAM Buffer async Tx queue
+ *			- reset the RAM Buffer sync Tx queue
+ *			- reset the MAC Tx FIFO
+ *		o switch Link and Tx LED off, stop the LED counters
+ *
+ *	If SK_STOP_RX is set,
+ *		o stop the port's receive queue
+ *		- The path data transfer activity is fully stopped now.
+ *		o perform a local reset of the port's Rx path
+ *			- reset the PCI FIFO of the Rx queue
+ *			- reset the RAM Buffer receive queue
+ *			- reset the MAC Rx FIFO
+ *		o switch Rx LED off, stop the LED counter
+ *
+ *	If all ports are stopped,
+ *		o reset the RAM Interface.
+ *
+ * Notes:
+ *	o This function may be called during the driver states RESET_PORT and
+ *	  SWITCH_PORT.
+ */
+void SkGeStopPort(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+int		Port,	/* port to stop (MAC_1 + n) */
+int		Dir,	/* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
+int		RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
+{
+#ifndef SK_DIAG
+	SK_EVPARA Para;
+#endif /* !SK_DIAG */
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+	SK_U32	XsCsr;
+	SK_U32	XaCsr;
+	SK_U64	ToutStart;
+	int		i;
+	int		ToutCnt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if ((Dir & SK_STOP_TX) != 0) {
+		/* disable receiver and transmitter */
+		SkMacRxTxDisable(pAC, IoC, Port);
+
+		/* stop both transmit queues */
+		/*
+		 * If the BMU is in the reset state CSR_STOP will terminate
+		 * immediately.
+		 */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP);
+
+		ToutStart = SkOsGetTime(pAC);
+		ToutCnt = 0;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate.
+			 */
+			SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_TX1 :
+				PA_CLR_TO_TX2);
+
+			/*
+			 * If the transfer stucks at the MAC the STOP command will not
+			 * terminate if we don't flush the XMAC's transmit FIFO !
+			 */
+			SkMacFlushTxFifo(pAC, IoC, Port);
+
+			XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
+			XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
+
+			if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
+				/*
+				 * Timeout of 1/18 second reached.
+				 * This needs to be checked at 1/18 sec only.
+				 */
+				ToutCnt++;
+				if (ToutCnt > 1) {
+					/* Might be a problem when the driver event handler
+					 * calls StopPort again. XXX.
+					 */
+
+					/* Fatal Error, Loop aborted */
+					SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
+						SKERR_HWI_E018MSG);
+#ifndef SK_DIAG
+					Para.Para64 = Port;
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+#endif /* !SK_DIAG */
+					return;
+				}
+				/*
+				 * Cache incoherency workaround: Assume a start command
+				 * has been lost while sending the frame.
+				 */
+				ToutStart = SkOsGetTime(pAC);
+
+				if ((XsCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
+				}
+				if ((XaCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
+				}
+			}
+
+			/*
+			 * Because of the ASIC problem report entry from 21.08.1998 it is
+			 * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
+			 */
+		} while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
+				 (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+		/* Reset the MAC depending on the RstMode */
+		if (RstMode == SK_SOFT_RST) {
+			SkMacSoftRst(pAC, IoC, Port);
+		}
+		else {
+			SkMacHardRst(pAC, IoC, Port);
+		}
+
+		/* Disable Force Sync bit and Enable Alloc bit */
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+			TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+		/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
+
+		/* Perform a local reset of the port's Tx path */
+
+		/* Reset the PCI FIFO of the async Tx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the PCI FIFO of the sync Tx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer async Tx queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
+		/* Reset the RAM Buffer sync Tx queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
+
+		/* Reset Tx MAC FIFO */
+		if (pAC->GIni.GIGenesis) {
+			/* Note: MFF_RST_SET does NOT reset the XMAC ! */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+			/* switch Link and Tx LED off, stop the LED counters */
+			/* Link LED is switched off by the RLMT and the Diag itself */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+		}
+		else {
+			/* Reset TX MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+		}
+	}
+
+	if ((Dir & SK_STOP_RX) != 0) {
+		/*
+		 * The RX Stop Command will not terminate if no buffers
+		 * are queued in the RxD ring. But it will always reach
+		 * the Idle state. Therefore we can use this feature to
+		 * stop the transfer of received packets.
+		 */
+		/* stop the port's receive queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);
+
+		i = 100;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate
+			 */
+			SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_RX1 :
+				PA_CLR_TO_RX2);
+
+			DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
+
+			/* timeout if i==0 (bug fix for #10748) */
+			if (--i == 0) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
+					SKERR_HWI_E024MSG);
+				break;
+			}
+			/*
+			 * because of the ASIC problem report entry from 21.08.98
+			 * it is required to wait until CSR_STOP is reset and
+			 * CSR_SV_IDLE is set.
+			 */
+		} while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+		/* The path data transfer activity is fully stopped now */
+
+		/* Perform a local reset of the port's Rx path */
+
+		 /*	Reset the PCI FIFO of the Rx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer receive queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
+
+		/* Reset Rx MAC FIFO */
+		if (pAC->GIni.GIGenesis) {
+
+			SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
+
+			/* switch Rx LED off, stop the LED counter */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
+		}
+		else {
+			/* Reset Rx MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+		}
+	}
+}	/* SkGeStopPort */
+
+
+/******************************************************************************
+ *
+ *	SkGeInit0() - Level 0 Initialization
+ *
+ * Description:
+ *	- Initialize the BMU address offsets
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit0(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int i;
+	SK_GEPORT *pPrt;
+
+	for (i = 0; i < SK_MAX_MACS; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		pPrt->PState = SK_PRT_RESET;
+		pPrt->PRxQOff = QOffTab[i].RxQOff;
+		pPrt->PXsQOff = QOffTab[i].XsQOff;
+		pPrt->PXaQOff = QOffTab[i].XaQOff;
+		pPrt->PCheckPar = SK_FALSE;
+		pPrt->PIsave = 0;
+		pPrt->PPrevShorts = 0;
+		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
+		pPrt->PPrevRx = 0;
+		pPrt->PPrevFcs = 0;
+		pPrt->PRxLim = SK_DEF_RX_WA_LIM;
+		pPrt->PLinkMode = SK_LMODE_AUTOFULL;
+		pPrt->PLinkSpeedCap = SK_LSPEED_CAP_1000MBPS;
+		pPrt->PLinkSpeed = SK_LSPEED_1000MBPS;
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_UNKNOWN;
+		pPrt->PLinkModeConf = SK_LMODE_AUTOSENSE;
+		pPrt->PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PLinkBroken = SK_TRUE; /* See WA code */
+		pPrt->PLinkCap = (SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
+				SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+		pPrt->PFlowCtrlCap = SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+		pPrt->PMSCap = 0;
+		pPrt->PMSMode = SK_MS_MODE_AUTO;
+		pPrt->PMSStatus = SK_MS_STAT_UNSET;
+		pPrt->PAutoNegFail = SK_FALSE;
+		pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+		pPrt->PHWLinkUp = SK_FALSE;
+	}
+
+	pAC->GIni.GIPortUsage = SK_RED_LINK;
+
+}	/* SkGeInit0*/
+
+#ifdef SK_PCI_RESET
+
+/******************************************************************************
+ *
+ *	SkGePciReset() - Reset PCI interface
+ *
+ * Description:
+ *	o Read PCI configuration.
+ *	o Change power state to 3.
+ *	o Change power state to 0.
+ *	o Restore PCI configuration.
+ *
+ * Returns:
+ *	0:	Success.
+ *	1:	Power state could not be changed to 3.
+ */
+static int SkGePciReset(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int		i;
+	SK_U16	PmCtlSts;
+	SK_U32	Bp1;
+	SK_U32	Bp2;
+	SK_U16	PciCmd;
+	SK_U8	Cls;
+	SK_U8	Lat;
+	SK_U8	ConfigSpace[PCI_CFG_SIZE];
+
+	/*
+	 * Note: Switching to D3 state is like a software reset.
+	 *		 Switching from D3 to D0 is a hardware reset.
+	 *		 We have to save and restore the configuration space.
+	 */
+	for (i = 0; i < PCI_CFG_SIZE; i++) {
+		SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]);
+	}
+
+	/* We know the RAM Interface Arbiter is enabled. */
+	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3);
+	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
+
+	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) {
+		return(1);
+	}
+
+	/* Return to D0 state. */
+	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0);
+
+	/* Check for D0 state. */
+	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
+
+	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) {
+		return(1);
+	}
+
+	/* Check PCI Config Registers. */
+	SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd);
+	SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls);
+	SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1);
+	SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2);
+	SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat);
+
+	if (PciCmd != 0 || Cls != 0 || (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1 ||
+		Lat != 0) {
+		return(1);
+	}
+
+	/* Restore PCI Config Space. */
+	for (i = 0; i < PCI_CFG_SIZE; i++) {
+		SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]);
+	}
+
+	return(0);
+}	/* SkGePciReset */
+
+#endif /* SK_PCI_RESET */
+
+/******************************************************************************
+ *
+ *	SkGeInit1() - Level 1 Initialization
+ *
+ * Description:
+ *	o Do a software reset.
+ *	o Clear all reset bits.
+ *	o Verify that the detected hardware is present.
+ *	  Return an error if not.
+ *	o Get the hardware configuration
+ *		+ Read the number of MACs/Ports.
+ *		+ Read the RAM size.
+ *		+ Read the PCI Revision Id.
+ *		+ Find out the adapters host clock speed
+ *		+ Read and check the PHY type
+ *
+ * Returns:
+ *	0:	success
+ *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
+ */
+static int SkGeInit1(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	SK_U8	Byte;
+	SK_U16	Word;
+	SK_U16	CtrlStat;
+	SK_U32	FlashAddr;
+	int	RetVal;
+	int	i;
+
+	RetVal = 0;
+
+	/* save CLK_RUN bits (YUKON-Lite) */
+	SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+#ifdef SK_PCI_RESET
+	(void)SkGePciReset(pAC, IoC);
+#endif /* SK_PCI_RESET */
+
+	/* do the SW-reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+	/* release the SW-reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
+
+	/* reset all error bits in the PCI STATUS register */
+	/*
+	 * Note: PCI Cfg cycles cannot be used, because they are not
+	 *		 available on some platforms after 'boot time'.
+	 */
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* release Master Reset */
+	SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
+
+#ifdef CLK_RUN
+	CtrlStat |= CS_CLK_RUN_ENA;
+#endif /* CLK_RUN */
+
+	/* restore CLK_RUN bits */
+	SK_OUT16(IoC, B0_CTST, CtrlStat &
+		(CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA));
+
+	/* read Chip Identification Number */
+	SK_IN8(IoC, B2_CHIP_ID, &Byte);
+	pAC->GIni.GIChipId = Byte;
+
+	/* read number of MACs */
+	SK_IN8(IoC, B2_MAC_CFG, &Byte);
+	pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+
+	/* get Chip Revision Number */
+	pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
+
+	/* get diff. PCI parameters */
+	SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+	/* read the adapters RAM size */
+	SK_IN8(IoC, B2_E_0, &Byte);
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+
+		pAC->GIni.GIGenesis = SK_TRUE;
+
+		if (Byte == 3) {
+			/* special case: 4 x 64k x 36, offset = 0x80000 */
+			pAC->GIni.GIRamSize = 1024;
+			pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+		}
+		else {
+			pAC->GIni.GIRamSize = (int)Byte * 512;
+			pAC->GIni.GIRamOffs = 0;
+		}
+		/* all GE adapters work with 53.125 MHz host clock */
+		pAC->GIni.GIHstClkFact = SK_FACT_53;
+
+		/* set Descr. Poll Timer Init Value to 250 ms */
+		pAC->GIni.GIPollTimerVal =
+			SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+	}
+	else {
+		pAC->GIni.GIGenesis = SK_FALSE;
+
+#ifndef VCPU
+		pAC->GIni.GIRamSize = (Byte == 0) ? 128 : (int)Byte * 4;
+#else
+		pAC->GIni.GIRamSize = 128;
+#endif
+		pAC->GIni.GIRamOffs = 0;
+
+		/* WA for chip Rev. A */
+		pAC->GIni.GIWolOffs = (pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
+
+		/* get PM Capabilities of PCI config space */
+		SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word);
+
+		/* check if VAUX is available */
+		if (((CtrlStat & CS_VAUX_AVAIL) != 0) &&
+			/* check also if PME from D3cold is set */
+			((Word & PCI_PME_D3C_SUP) != 0)) {
+			/* set entry in GE init struct */
+			pAC->GIni.GIVauxAvail = SK_TRUE;
+		}
+
+		/* save Flash-Address Register */
+		SK_IN32(IoC, B2_FAR, &FlashAddr);
+
+		/* test Flash-Address Register */
+		SK_OUT8(IoC, B2_FAR + 3, 0xff);
+		SK_IN8(IoC, B2_FAR + 3, &Byte);
+
+		pAC->GIni.GIYukonLite = (SK_BOOL)(Byte != 0);
+
+		/* restore Flash-Address Register */
+		SK_OUT32(IoC, B2_FAR, FlashAddr);
+
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			/* set GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+
+			/* clear GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+		}
+		/* all YU chips work with 78.125 MHz host clock */
+		pAC->GIni.GIHstClkFact = SK_FACT_78;
+
+		pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;	/* 215 ms */
+	}
+
+	/* check if 64-bit PCI Slot is present */
+	pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);
+
+	/* check if 66 MHz PCI Clock is active */
+	pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);
+
+	/* read PCI HW Revision Id. */
+	SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+	pAC->GIni.GIPciHwRev = Byte;
+
+	/* read the PMD type */
+	SK_IN8(IoC, B2_PMD_TYP, &Byte);
+	pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');
+
+	/* read the PHY type */
+	SK_IN8(IoC, B2_E_1, &Byte);
+
+	Byte &= 0x0f;	/* the PHY type is stored in the lower nibble */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+		if (pAC->GIni.GIGenesis) {
+			switch (Byte) {
+			case SK_PHY_XMAC:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
+				break;
+			case SK_PHY_BCOM:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+				pAC->GIni.GP[i].PMSCap =
+					SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
+				break;
+#ifdef OTHER_PHY
+			case SK_PHY_LONE:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
+				break;
+			case SK_PHY_NAT:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
+				break;
+#endif /* OTHER_PHY */
+			default:
+				/* ERROR: unexpected PHY type detected */
+				RetVal = 5;
+				break;
+			}
+		}
+		else {
+			if (Byte == 0) {
+				/* if this field is not initialized */
+				Byte = SK_PHY_MARV_COPPER;
+				pAC->GIni.GICopperType = SK_TRUE;
+			}
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;
+
+			if (pAC->GIni.GICopperType) {
+				pAC->GIni.GP[i].PLinkSpeedCap = SK_LSPEED_CAP_AUTO |
+					SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
+					SK_LSPEED_CAP_1000MBPS;
+				pAC->GIni.GP[i].PLinkSpeed = SK_LSPEED_AUTO;
+				pAC->GIni.GP[i].PMSCap =
+					SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
+			}
+			else {
+				Byte = SK_PHY_MARV_FIBER;
+			}
+		}
+
+		pAC->GIni.GP[i].PhyType = Byte;
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("PHY type: %d  PHY addr: %04x\n", Byte,
+			pAC->GIni.GP[i].PhyAddr));
+	}
+
+	/* get Mac Type & set function pointers dependent on */
+	if (pAC->GIni.GIGenesis) {
+		pAC->GIni.GIMacType = SK_MAC_XMAC;
+
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkXmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkXmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkXmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkXmOverflowStatus;
+	}
+	else {
+		pAC->GIni.GIMacType = SK_MAC_GMAC;
+
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkGmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkGmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkGmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkGmOverflowStatus;
+
+#ifdef SPECIAL_HANDLING
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+			/* check HW self test result */
+			SK_IN8(IoC, B2_E_3, &Byte);
+			if ((Byte & B2_E3_RES_MASK) != 0) {
+				RetVal = 6;
+			}
+		}
+#endif
+	}
+	return(RetVal);
+}	/* SkGeInit1 */
+
+
+/******************************************************************************
+ *
+ *	SkGeInit2() - Level 2 Initialization
+ *
+ * Description:
+ *	- start the Blink Source Counter
+ *	- start the Descriptor Poll Timer
+ *	- configure the MAC-Arbiter
+ *	- configure the Packet-Arbiter
+ *	- enable the Tx Arbiters
+ *	- enable the RAM Interface Arbiter
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit2(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	SK_U32	DWord;
+	int		i;
+
+	/* start the Descriptor Poll Timer */
+	if (pAC->GIni.GIPollTimerVal != 0) {
+		if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
+			pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
+		}
+		SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
+		SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
+	}
+
+	if (pAC->GIni.GIGenesis) {
+		/* start the Blink Source Counter */
+		DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+
+		SK_OUT32(IoC, B2_BSC_INI, DWord);
+		SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+		/*
+		 * Configure the MAC Arbiter and the Packet Arbiter.
+		 * They will be started once and never be stopped.
+		 */
+		SkGeInitMacArb(pAC, IoC);
+
+		SkGeInitPktArb(pAC, IoC);
+	}
+	else {
+		/* start Time Stamp Timer */
+		SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
+	}
+
+	/* enable the Tx Arbiters */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
+	}
+
+	/* enable the RAM Interface Arbiter */
+	SkGeInitRamIface(pAC, IoC);
+
+}	/* SkGeInit2 */
+
+/******************************************************************************
+ *
+ *	SkGeInit() - Initialize the GE Adapter with the specified level.
+ *
+ * Description:
+ *	Level	0:	Initialize the Module structures.
+ *	Level	1:	Generic Hardware Initialization. The IOP/MemBase pointer has
+ *				to be set before calling this level.
+ *
+ *			o Do a software reset.
+ *			o Clear all reset bits.
+ *			o Verify that the detected hardware is present.
+ *			  Return an error if not.
+ *			o Get the hardware configuration
+ *				+ Set GIMacsFound with the number of MACs.
+ *				+ Store the RAM size in GIRamSize.
+ *				+ Save the PCI Revision ID in GIPciHwRev.
+ *			o return an error
+ *				if Number of MACs > SK_MAX_MACS
+ *
+ *			After returning from Level 0 the adapter
+ *			may be accessed with IO operations.
+ *
+ *	Level	2:	start the Blink Source Counter
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Number of MACs exceeds SK_MAX_MACS	(after level 1)
+ *	2:	Adapter not present or not accessible
+ *	3:	Illegal initialization level
+ *	4:	Initialization Level 1 Call missing
+ *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
+ */
+int	SkGeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Level)		/* initialization level */
+{
+	int		RetVal;		/* return value */
+	SK_U32	DWord;
+
+	RetVal = 0;
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+		("SkGeInit(Level %d)\n", Level));
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		/* Initialization Level 0 */
+		SkGeInit0(pAC, IoC);
+		pAC->GIni.GILevel = SK_INIT_DATA;
+		break;
+
+	case SK_INIT_IO:
+		/* Initialization Level 1 */
+		RetVal = SkGeInit1(pAC, IoC);
+		if (RetVal != 0) {
+			break;
+		}
+
+		/* check if the adapter seems to be accessible */
+		SK_OUT32(IoC, B2_IRQM_INI, 0x11335577L);
+		SK_IN32(IoC, B2_IRQM_INI, &DWord);
+		SK_OUT32(IoC, B2_IRQM_INI, 0L);
+
+		if (DWord != 0x11335577L) {
+			RetVal = 2;
+			break;
+		}
+
+		/* check if the number of GIMacsFound matches SK_MAX_MACS */
+		if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
+			RetVal = 1;
+			break;
+		}
+
+		/* Level 1 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_IO;
+		break;
+
+	case SK_INIT_RUN:
+		/* Initialization Level 2 */
+		if (pAC->GIni.GILevel != SK_INIT_IO) {
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
+#endif /* !SK_DIAG */
+			RetVal = 4;
+			break;
+		}
+		SkGeInit2(pAC, IoC);
+
+		/* Level 2 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_RUN;
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
+		RetVal = 3;
+		break;
+	}
+
+	return(RetVal);
+}	/* SkGeInit */
+
+
+/******************************************************************************
+ *
+ *	SkGeDeInit() - Deinitialize the adapter
+ *
+ * Description:
+ *	All ports of the adapter will be stopped if not already done.
+ *	Do a software reset and switch off all LEDs.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeDeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int	i;
+	SK_U16	Word;
+
+#ifndef VCPU
+	/* ensure I2C is ready */
+	SkI2cWaitIrq(pAC, IoC);
+#endif
+
+	/* stop all current transfer activity */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
+			pAC->GIni.GP[i].PState != SK_PRT_RESET) {
+
+			SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
+		}
+	}
+
+	/* Reset all bits in the PCI STATUS register */
+	/*
+	 * Note: PCI Cfg cycles cannot be used, because they are not
+	 *	 available on some platforms after 'boot time'.
+	 */
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* do the reset, all LEDs are switched off now */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+}	/* SkGeDeInit */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitPort()	Initialize the specified port.
+ *
+ * Description:
+ *	PRxQSize, PXSQSize, and PXAQSize has to be
+ *	configured for the specified port before calling this function.
+ *  The descriptor rings has to be initialized too.
+ *
+ *	o (Re)configure queues of the specified port.
+ *	o configure the MAC of the specified port.
+ *	o put ASIC and MAC(s) in operational mode.
+ *	o initialize Rx/Tx and Sync LED
+ *	o initialize RAM Buffers and MAC FIFOs
+ *
+ *	The port is ready to connect when returning.
+ *
+ * Note:
+ *	The MAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Queue size initialization error. The configured values
+ *		for PRxQSize, PXSQSize, or PXAQSize are invalid for one
+ *		or more queues. The specified port was NOT initialized.
+ *		An error log entry was generated.
+ *	2:	The port has to be stopped before it can be initialized again.
+ */
+int SkGeInitPort(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port to configure */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (SkGeCheckQSize(pAC, Port) != 0) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
+		return(1);
+	}
+
+	if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
+		return(2);
+	}
+
+	/* configuration ok, initialize the Port now */
+
+	if (pAC->GIni.GIGenesis) {
+		/* initialize Rx, Tx and Link LED */
+		/*
+		 * If 1000BT Phy needs LED initialization than swap
+		 * LED and XMAC initialization order
+		 */
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
+		/* The Link LED is initialized by RLMT or Diagnostics itself */
+
+		SkXmInitMac(pAC, IoC, Port);
+	}
+	else {
+
+		SkGmInitMac(pAC, IoC, Port);
+	}
+
+	/* do NOT initialize the Link Sync Counter */
+
+	SkGeInitMacFifo(pAC, IoC, Port);
+
+	SkGeInitRamBufs(pAC, IoC, Port);
+
+	if (pPrt->PXSQSize != 0) {
+		/* enable Force Sync bit if synchronous queue available */
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
+	}
+
+	SkGeInitBmu(pAC, IoC, Port);
+
+	/* mark port as initialized */
+	pPrt->PState = SK_PRT_INIT;
+
+	return(0);
+}	/* SkGeInitPort */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c
new file mode 100644
index 0000000..4a9e9e6
--- /dev/null
+++ b/drivers/net/sk98lin/skgemib.c
@@ -0,0 +1,1060 @@
+/*****************************************************************************
+ *
+ * Name:	skgemib.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 2002/12/16 09:04:34 $
+ * Purpose:	Private Network Management Interface Management Database
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgemib.c,v $
+ *	Revision 1.7  2002/12/16 09:04:34  tschilli
+ *	Code for VCT handling added.
+ *
+ *	Revision 1.6  2002/08/09 15:40:21  rwahl
+ *	Editorial change (renamed ConfSpeedCap).
+ *
+ *	Revision 1.5  2002/08/09 11:05:34  rwahl
+ *	Added oid handling for link speed cap.
+ *
+ *	Revision 1.4  2002/08/09 09:40:27  rwahl
+ *	Added support for NDIS OID_PNP_xxx.
+ *
+ *	Revision 1.3  2002/07/17 19:39:54  rwahl
+ *	Added handler for OID_SKGE_SPEED_MODE & OID_SKGE_SPEED_STATUS.
+ *
+ *	Revision 1.2  2002/05/22 08:59:00  rwahl
+ *	- static functions only for release build.
+ *	- Source file must be included.
+ *
+ *	Revision 1.1  2002/05/22 08:12:42  rwahl
+ *	Initial version.
+ *
+ ****************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+ * PRIVATE OID handler function prototypes
+ */
+PNMI_STATIC int Addr(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int* pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+
+#ifdef SK_POWER_MGMT
+PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+#endif
+
+
+/* defines *******************************************************************/
+#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+
+
+/* global variables **********************************************************/
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {
+	{OID_GEN_XMIT_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+	{OID_GEN_RCV_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+	{OID_GEN_XMIT_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_NO_BUFFER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_DIRECTED_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+	{OID_GEN_DIRECTED_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+	{OID_GEN_RCV_CRC_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+	{OID_GEN_TRANSMIT_QUEUE_LENGTH,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_802_3_PERMANENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_CURRENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_RCV_ERROR_ALIGNMENT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+	{OID_802_3_XMIT_ONE_COLLISION,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_802_3_XMIT_MORE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+	{OID_802_3_XMIT_DEFERRED,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+	{OID_802_3_XMIT_MAX_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_802_3_RCV_OVERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+	{OID_802_3_XMIT_UNDERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+	{OID_802_3_XMIT_TIMES_CRS_LOST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+	{OID_802_3_XMIT_LATE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+#ifdef SK_POWER_MGMT
+	{OID_PNP_CAPABILITIES,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_SET_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_QUERY_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_ADD_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_REMOVE_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_ENABLE_WAKE_UP,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, PowerManagement, 0},
+#endif /* SK_POWER_MGMT */
+	{OID_SKGE_MDB_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MgmtDBVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SUPPORTED_LIST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ALL_DATA,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, OidStruct, 0},
+	{OID_SKGE_VPD_FREE_BYTES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdFreeBytes),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_LIST,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesList),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesNumber),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_KEY,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_VALUE,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACCESS,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACTION,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+		SK_PNMI_RW, Vpd, 0},
+	{OID_SKGE_PORT_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(PortNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DEVICE_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DeviceType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHIPSET,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Chipset),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ACTION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Action),
+		SK_PNMI_RW, Perform, 0},
+	{OID_SKGE_RESULT,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TestResult),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_SPEED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusSpeed),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_WIDTH,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusWidth),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_LEN,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueLen),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_MAX,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueMax),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_RETRY,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxRetryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_USED_DESCR_NO,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxUsedDescrNo),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_DELIVERED_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_OCTETS_DELIV_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_IN_ERRORS_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(InErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_OUT_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(OutErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ERR_RECOVERY_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ErrRecoveryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SYSUPTIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SysUpTime),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SensorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_INDEX,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_DESCR,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_TYPE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_VALUE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_STATUS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_CHKSM_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ChecksumNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHKSM_RX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_ERR_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_STAT_TX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+	{OID_SKGE_STAT_TX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+	{OID_SKGE_STAT_TX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+	{OID_SKGE_STAT_TX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+	{OID_SKGE_STAT_TX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+	{OID_SKGE_STAT_TX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+	{OID_SKGE_STAT_TX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+	{OID_SKGE_STAT_TX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+	{OID_SKGE_STAT_TX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+	{OID_SKGE_STAT_TX_SINGLE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_SKGE_STAT_TX_MULTI_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+	{OID_SKGE_STAT_TX_EXCESS_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_SKGE_STAT_TX_LATE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+	{OID_SKGE_STAT_TX_DEFFERAL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+	{OID_SKGE_STAT_TX_EXCESS_DEF,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+	{OID_SKGE_STAT_TX_UNDERRUN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+	{OID_SKGE_STAT_TX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/*	{OID_SKGE_STAT_TX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_TX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+	{OID_SKGE_STAT_TX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+	{OID_SKGE_STAT_TX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+	{OID_SKGE_STAT_TX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+	{OID_SKGE_STAT_TX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+	{OID_SKGE_STAT_TX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+	{OID_SKGE_STAT_TX_SYNC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+	{OID_SKGE_STAT_TX_SYNC_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+	{OID_SKGE_STAT_RX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+	{OID_SKGE_STAT_RX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+	{OID_SKGE_STAT_RX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+	{OID_SKGE_STAT_RX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+	{OID_SKGE_STAT_RX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+	{OID_SKGE_STAT_RX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
+	{OID_SKGE_STAT_RX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+	{OID_SKGE_STAT_RX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+	{OID_SKGE_STAT_RX_PFLOWC_ERR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+	{OID_SKGE_STAT_RX_FLOWC_UNKWN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+	{OID_SKGE_STAT_RX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+	{OID_SKGE_STAT_RX_MISSED,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+	{OID_SKGE_STAT_RX_FRAMING,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+	{OID_SKGE_STAT_RX_OVERFLOW,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+	{OID_SKGE_STAT_RX_JABBER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+	{OID_SKGE_STAT_RX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+	{OID_SKGE_STAT_RX_IR_LENGTH,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+	{OID_SKGE_STAT_RX_SYMBOL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+	{OID_SKGE_STAT_RX_SHORTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+	{OID_SKGE_STAT_RX_RUNT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+	{OID_SKGE_STAT_RX_CEXT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+	{OID_SKGE_STAT_RX_TOO_LONG,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+	{OID_SKGE_STAT_RX_FCS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/*	{OID_SKGE_STAT_RX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_RX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+	{OID_SKGE_STAT_RX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+	{OID_SKGE_STAT_RX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+	{OID_SKGE_STAT_RX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+	{OID_SKGE_STAT_RX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+	{OID_SKGE_STAT_RX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+	{OID_SKGE_PHYS_CUR_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+		SK_PNMI_RW, Addr, 0},
+	{OID_SKGE_PHYS_FAC_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+		SK_PNMI_RO, Addr, 0},
+	{OID_SKGE_PMD,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_CONNECTOR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_TRAP,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Trap),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TRAP_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TrapNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MODE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMode),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortNumber),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_ACTIVE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortActive),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_PREFERRED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortPreferred),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeCts),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_TIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeTime),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_ESTIM,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_THRES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_INDEX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_SP_REQ_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_SP_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_MONITOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MONITOR_INDEX,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADDR,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ERRS,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADMIN,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
+		SK_PNMI_RW, Monitor, 0},
+	{OID_SKGE_MTU,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MtuSize),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_VCT_GET,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+	{OID_SKGE_VCT_SET,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, Vct, 0},
+	{OID_SKGE_VCT_STATUS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+};
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
new file mode 100644
index 0000000..b5d32b0
--- /dev/null
+++ b/drivers/net/sk98lin/skgepnmi.c
@@ -0,0 +1,8310 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.102 $
+ * Date:	$Date: 2002/12/16 14:03:24 $
+ * Purpose:	Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnmi.c,v $
+ *	Revision 1.102  2002/12/16 14:03:24  tschilli
+ *	VCT code in Vct() changed.
+ *
+ *	Revision 1.101  2002/12/16 09:04:10  tschilli
+ *	Code for VCT handling added.
+ *
+ *	Revision 1.100  2002/09/26 14:28:13  tschilli
+ *	For XMAC the values in the SK_PNMI_PORT Port struct are copied to
+ *	the new SK_PNMI_PORT BufPort struct during a MacUpdate() call.
+ *	These values are used when GetPhysStatVal() is called. With this
+ *	mechanism you get the best results when software corrections for
+ *	counters are needed. Example: RX_LONGFRAMES.
+ *
+ *	Revision 1.99  2002/09/17 12:31:19  tschilli
+ *	OID_SKGE_TX_HW_ERROR_CTS, OID_SKGE_OUT_ERROR_CTS, OID_GEN_XMIT_ERROR:
+ *	Double count of SK_PNMI_HTX_EXCESS_COL in function General() removed.
+ *	OID_PNP_CAPABILITIES: sizeof(SK_PM_WAKE_UP_CAPABILITIES) changed to
+ *	sizeof(SK_PNP_CAPABILITIES) in function PowerManagement().
+ *
+ *	Revision 1.98  2002/09/10 09:00:03  rwahl
+ *	Adapted boolean definitions according sktypes.
+ *
+ *	Revision 1.97  2002/09/05 15:07:03  rwahl
+ *	Editorial changes.
+ *
+ *	Revision 1.96  2002/09/05 11:04:14  rwahl
+ *	- Rx/Tx packets statistics of virtual port were zero on link down (#10750)
+ *	- For GMAC the overflow IRQ for Rx longframe counter was not counted.
+ *	- Incorrect calculation for oids OID_SKGE_RX_HW_ERROR_CTS,
+ *	  OID_SKGE_IN_ERRORS_CTS,  OID_GEN_RCV_ERROR.
+ *	- Moved correction for OID_SKGE_STAT_RX_TOO_LONG to GetPhysStatVal().
+ *	- Editorial changes.
+ *
+ *	Revision 1.95  2002/09/04 08:53:37  rwahl
+ *	- Incorrect statistics for Rx_too_long counter with jumbo frame (#10751)
+ *	- StatRxFrameTooLong & StatRxPMaccErr counters were not reset.
+ *	- Fixed compiler warning for debug msg arg types.
+ *
+ *	Revision 1.94  2002/08/09 15:42:14  rwahl
+ *	- Fixed StatAddr table for GMAC.
+ *	- VirtualConf(): returned indeterminated status for speed oids if no
+ *	  active port.
+ *
+ *	Revision 1.93  2002/08/09 11:04:59  rwahl
+ *	Added handler for link speed caps.
+ *
+ *	Revision 1.92  2002/08/09 09:43:03  rwahl
+ *	- Added handler for NDIS OID_PNP_xxx ids.
+ *
+ *	Revision 1.91  2002/07/17 19:53:03  rwahl
+ *	- Added StatOvrflwBit table for XMAC & GMAC.
+ *	- Extended StatAddr table for GMAC. Added check of number of counters
+ *	  in enumeration and size of StatAddr table on init level.
+ *	- Added use of GIFunc table.
+ *	- ChipSet is not static anymore,
+ *	- Extended SIRQ event handler for both mac types.
+ *	- Fixed rx short counter bug (#10620)
+ *	- Added handler for oids SKGE_SPEED_MODE & SKGE_SPEED_STATUS.
+ *	- Extendet GetPhysStatVal() for GMAC.
+ *	- Editorial changes.
+ *
+ *	Revision 1.90  2002/05/22 08:56:25  rwahl
+ *	- Moved OID table to separate source file.
+ *	- Fix: TX_DEFFERAL counter incremented in full-duplex mode.
+ *	- Use string definitions for error msgs.
+ *
+ *	Revision 1.89  2001/09/18 10:01:30  mkunz
+ *	some OID's fixed for dualnetmode
+ *
+ *	Revision 1.88  2001/08/02 07:58:08  rwahl
+ *	- Fixed NetIndex to csum module at ResetCounter().
+ *
+ *	Revision 1.87  2001/04/06 13:35:09  mkunz
+ *	-Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's
+ *
+ *	Revision 1.86  2001/03/09 09:18:03  mkunz
+ *	Changes in SK_DBG_MSG
+ *
+ *	Revision 1.85  2001/03/08 09:37:31  mkunz
+ *	Bugfix in ResetCounter for Pnmi.Port structure
+ *
+ *	Revision 1.84  2001/03/06 09:04:55  mkunz
+ *	Made some changes in instance calculation
+ *
+ *	Revision 1.83  2001/02/15 09:15:32  mkunz
+ *	Necessary changes for dual net mode added
+ *
+ *	Revision 1.82  2001/02/07 08:24:19  mkunz
+ *	-Made changes in handling of OID_SKGE_MTU
+ *
+ *	Revision 1.81  2001/02/06 09:58:00  mkunz
+ *	-Vpd bug fixed
+ *	-OID_SKGE_MTU added
+ *	-pnmi support for dual net mode. Interface function and macros extended
+ *
+ *	Revision 1.80  2001/01/22 13:41:35  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.79  2000/12/05 14:57:40  cgoos
+ *	SetStruct failed before first Link Up (link mode of virtual
+ *	port "INDETERMINATED").
+ *
+ *	Revision 1.78  2000/09/12 10:44:58  cgoos
+ *	Fixed SK_PNMI_STORE_U32 calls with typecasted argument.
+ *
+ *	Revision 1.77  2000/09/07 08:10:19  rwahl
+ *	- Modified algorithm for 64bit NDIS statistic counters;
+ *	  returns 64bit or 32bit value depending on passed buffer
+ *	  size. Indicate capability for 64bit NDIS counter, if passed
+ *	  buffer size is zero. OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR,
+ *	  and OID_GEN_RCV_NO_BUFFER handled as 64bit counter, too.
+ *	- corrected OID_SKGE_RLMT_PORT_PREFERRED.
+ *
+ *	Revision 1.76  2000/08/03 15:23:39  rwahl
+ *	- Correction for FrameTooLong counter has to be moved to OID handling
+ *	  routines (instead of statistic counter routine).
+ *	- Fix in XMAC Reset Event handling: Only offset counter for hardware
+ *	  statistic registers are updated.
+ *
+ *	Revision 1.75  2000/08/01 16:46:05  rwahl
+ *	- Added StatRxLongFrames counter and correction of FrameTooLong counter.
+ *	- Added directive to control width (default = 32bit) of NDIS statistic
+ *	  counters (SK_NDIS_64BIT_CTR).
+ *
+ *	Revision 1.74  2000/07/04 11:41:53  rwahl
+ *	- Added volition connector type.
+ *
+ *	Revision 1.73  2000/03/15 16:33:10  rwahl
+ *	Fixed bug 10510; wrong reset of virtual port statistic counters.
+ *
+ *	Revision 1.72  1999/12/06 16:15:53  rwahl
+ *	Fixed problem of instance range for current and factory MAC address.
+ *
+ *	Revision 1.71  1999/12/06 10:14:20  rwahl
+ *	Fixed bug 10476; set operation for PHY_OPERATION_MODE.
+ *
+ *	Revision 1.70  1999/11/22 13:33:34  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.69  1999/10/18 11:42:15  rwahl
+ *	Added typecasts for checking event dependent param (debug only).
+ *
+ *	Revision 1.68  1999/10/06 09:35:59  cgoos
+ *	Added state check to PHY_READ call (hanged if called during startup).
+ *
+ *	Revision 1.67  1999/09/22 09:53:20  rwahl
+ *	- Read Broadcom register for updating fcs error counter (1000Base-T).
+ *
+ *	Revision 1.66  1999/08/26 13:47:56  rwahl
+ *	Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap.
+ *
+ *	Revision 1.65  1999/07/26 07:49:35  cgoos
+ *	Added two typecasts to avoid compiler warnings.
+ *
+ *	Revision 1.64  1999/05/20 09:24:12  cgoos
+ *	Changes for 1000Base-T (sensors, Master/Slave).
+ *
+ *	Revision 1.63  1999/04/13 15:11:58  mhaveman
+ *	Moved include of rlmt.h to header skgepnmi.h because some macros
+ *	are needed there.
+ *
+ *	Revision 1.62  1999/04/13 15:08:07  mhaveman
+ *	Replaced again SK_RLMT_CHECK_LINK with SK_PNMI_RLMT_MODE_CHK_LINK
+ *	to grant unified interface by only using the PNMI header file.
+ *	SK_PNMI_RLMT_MODE_CHK_LINK is defined the same as SK_RLMT_CHECK_LINK.
+ *
+ *	Revision 1.61  1999/04/13 15:02:48  mhaveman
+ *	Changes caused by review:
+ *	-Changed some comments
+ *	-Removed redundant check for OID_SKGE_PHYS_FAC_ADDR
+ *	-Optimized PRESET check.
+ *	-Meaning of error SK_ADDR_DUPLICATE_ADDRESS changed. Set of same
+ *	 address will now not cause this error. Removed corresponding check.
+ *
+ *	Revision 1.60  1999/03/23 10:41:23  mhaveman
+ *	Added comments.
+ *
+ *	Revision 1.59  1999/02/19 08:01:28  mhaveman
+ *	Fixed bug 10372 that after counter reset all ports were displayed
+ *	as inactive.
+ *
+ *	Revision 1.58  1999/02/16 18:04:47  mhaveman
+ *	Fixed problem of twisted OIDs SENSOR_WAR_TIME and SENSOR_ERR_TIME.
+ *
+ *	Revision 1.56  1999/01/27 12:29:11  mhaveman
+ *	SkTimerStart was called with time value in milli seconds but needs
+ *	micro seconds.
+ *
+ *	Revision 1.55  1999/01/25 15:00:38  mhaveman
+ *	Added support to allow multiple ports to be active. If this feature in
+ *	future will be used, the Management Data Base variables PORT_ACTIVE
+ *	and PORT_PREFERED should be moved to the port specific part of RLMT.
+ *	Currently they return the values of the first active physical port
+ *	found. A set to the virtual port will actually change all active
+ *	physical ports. A get returns the melted values of all active physical
+ *	ports. If the port values differ a return value INDETERMINATED will
+ *	be returned. This effects especially the CONF group.
+ *
+ *	Revision 1.54  1999/01/19 10:10:22  mhaveman
+ *	-Fixed bug 10354: Counter values of virtual port were wrong after port
+ *	 switches
+ *	-Added check if a switch to the same port is notified.
+ *
+ *	Revision 1.53  1999/01/07 09:25:21  mhaveman
+ *	Forgot to initialize a variable.
+ *
+ *	Revision 1.52  1999/01/05 10:34:33  mhaveman
+ *	Fixed little error in RlmtChangeEstimate calculation.
+ *
+ *	Revision 1.51  1999/01/05 09:59:07  mhaveman
+ *	-Moved timer start to init level 2
+ *	-Redesigned port switch average calculation to avoid 64bit
+ *	 arithmetic.
+ *
+ *	Revision 1.50  1998/12/10 15:13:59  mhaveman
+ *	-Fixed: PHYS_CUR_ADDR returned wrong addresses
+ *	-Fixed: RLMT_PORT_PREFERED and RLMT_CHANGE_THRES preset returned
+ *	        always BAD_VALUE.
+ *	-Fixed: TRAP buffer seemed to sometimes suddenly empty
+ *
+ *	Revision 1.49  1998/12/09 16:17:07  mhaveman
+ *	Fixed: Couldnot delete VPD keys on UNIX.
+ *
+ *	Revision 1.48  1998/12/09 14:11:10  mhaveman
+ *	-Add: Debugmessage for XMAC_RESET supressed to minimize output.
+ *	-Fixed: RlmtChangeThreshold will now be initialized.
+ *	-Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char.
+ *	-Fixed: On VPD key creation an invalid key name could be created
+ *	        (e.g. A5)
+ *	-Some minor changes in comments and code.
+ *
+ *	Revision 1.47  1998/12/08 16:00:31  mhaveman
+ *	-Fixed: For RLMT_PORT_ACTIVE will now be returned a 0 if no port
+ *		is active.
+ *	-Fixed: For the RLMT statistics group only the last value was
+ *		returned and the rest of the buffer was filled with 0xff
+ *	-Fixed: Mysteriously the preset on RLMT_MODE still returned
+ *		BAD_VALUE.
+ *	Revision 1.46  1998/12/08 10:04:56  mhaveman
+ *	-Fixed: Preset on RLMT_MODE returned always BAD_VALUE error.
+ *	-Fixed: Alignment error in GetStruct
+ *	-Fixed: If for Get/Preset/SetStruct the buffer size is equal or
+ *	        larger than SK_PNMI_MIN_STRUCT_SIZE the return value is stored
+ *		to the buffer. In this case the caller should always return
+ *	        ok to its upper routines. Only if the buffer size is less
+ *	        than SK_PNMI_MIN_STRUCT_SIZE and the return value is unequal
+ *	        to 0, an error should be returned by the caller.
+ *	-Fixed: Wrong number of instances with RLMT statistic.
+ *	-Fixed: Return now SK_LMODE_STAT_UNKNOWN if the LinkModeStatus is 0.
+ *
+ *	Revision 1.45  1998/12/03 17:17:24  mhaveman
+ *	-Removed for VPD create action the buffer size limitation to 4 bytes.
+ *	-Pass now physical/active physical port to ADDR for CUR_ADDR set
+ *
+ *	Revision 1.44  1998/12/03 15:14:35  mhaveman
+ *	Another change to Vpd instance evaluation.
+ *
+ *	Revision 1.43  1998/12/03 14:18:10  mhaveman
+ *	-Fixed problem in PnmiSetStruct. It was impossible to set any value.
+ *	-Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION.
+ *
+ *	Revision 1.42  1998/12/03 11:31:47  mhaveman
+ *	Inserted cast to satisfy lint.
+ *
+ *	Revision 1.41  1998/12/03 11:28:16  mhaveman
+ *	Removed SK_PNMI_CHECKPTR
+ *
+ *	Revision 1.40  1998/12/03 11:19:07  mhaveman
+ *	Fixed problems
+ *	-A set to virtual port will now be ignored. A set with broadcast
+ *	 address to any port will be ignored.
+ *	-GetStruct function made VPD instance calculation wrong.
+ *	-Prefered port returned -1 instead of 0.
+ *
+ *	Revision 1.39  1998/11/26 15:30:29  mhaveman
+ *	Added sense mode to link mode.
+ *
+ *	Revision 1.38  1998/11/23 15:34:00  mhaveman
+ *	-Fixed bug for RX counters. On an RX overflow interrupt the high
+ *	 words of all RX counters were incremented.
+ *	-SET operations on FLOWCTRL_MODE and LINK_MODE accept now the
+ *	 value 0, which has no effect. It is usefull for multiple instance
+ *	 SETs.
+ *
+ *	Revision 1.37  1998/11/20 08:02:04  mhaveman
+ *	-Fixed: Ports were compared with MAX_SENSORS
+ *	-Fixed: Crash in GetTrapEntry with MEMSET macro
+ *	-Fixed: Conversions between physical, logical port index and instance
+ *
+ *	Revision 1.36  1998/11/16 07:48:53  mhaveman
+ *	Casted SK_DRIVER_SENDEVENT with (void) to eleminate compiler warnings
+ *	on Solaris.
+ *
+ *	Revision 1.35  1998/11/16 07:45:34  mhaveman
+ *	SkAddrOverride now returns value and will be checked.
+ *
+ *	Revision 1.34  1998/11/10 13:40:37  mhaveman
+ *	Needed to change interface, because NT driver needs a return value
+ *	of needed buffer space on TOO_SHORT errors. Therefore all
+ *	SkPnmiGet/Preset/Set functions now have a pointer to the length
+ *	parameter, where the needed space on error is returned.
+ *
+ *	Revision 1.33  1998/11/03 13:52:46  mhaveman
+ *	Made file lint conform.
+ *
+ *	Revision 1.32  1998/11/03 13:19:07  mhaveman
+ *	The events SK_HWEV_SET_LMODE and SK_HWEV_SET_FLOWMODE pass now in
+ *	Para32[0] the physical MAC index and in Para32[1] the new mode.
+ *
+ *	Revision 1.31  1998/11/03 12:30:40  gklug
+ *	fix: compiler warning memset
+ *
+ *	Revision 1.30  1998/11/03 12:04:46  mhaveman
+ *	Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end
+ *	Fixed alignment problem with CHIPSET.
+ *
+ *	Revision 1.29  1998/11/02 11:23:54  mhaveman
+ *	Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry.
+ *
+ *	Revision 1.28  1998/11/02 10:47:16  mhaveman
+ *	Added syslog messages for internal errors.
+ *
+ *	Revision 1.27  1998/10/30 15:48:06  mhaveman
+ *	Fixed problems after simulation of SK_PNMI_EVT_CHG_EST_TIMER and
+ *	RlmtChangeThreshold calculation.
+ *
+ *	Revision 1.26  1998/10/29 15:36:55  mhaveman
+ *	-Fixed bug in trap buffer handling.
+ *	-OID_SKGE_DRIVER_DESCR, OID_SKGE_DRIVER_VERSION, OID_SKGE_HW_DESCR,
+ *	 OID_SKGE_HW_VERSION, OID_SKGE_VPD_ENTRIES_LIST, OID_SKGE_VPD_KEY,
+ *	 OID_SKGE_VPD_VALUE, and OID_SKGE_SENSOR_DESCR return values with
+ *	 a leading octet before each string storing the string length.
+ *	-Perform a RlmtUpdate during SK_PNMI_EVT_XMAC_RESET to minimize
+ *	 RlmtUpdate calls in GetStatVal.
+ *	-Inserted SK_PNMI_CHECKFLAGS macro increase readability.
+ *
+ *	Revision 1.25  1998/10/29 08:50:36  mhaveman
+ *	Fixed problems after second event simulation.
+ *
+ *	Revision 1.24  1998/10/28 08:44:37  mhaveman
+ *	-Fixed alignment problem
+ *	-Fixed problems during event simulation
+ *	-Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT)
+ *	-Changed type of parameter Instance back to SK_U32 because of VPD
+ *	-Updated new VPD function calls
+ *
+ *	Revision 1.23  1998/10/23 10:16:37  mhaveman
+ *	Fixed bugs after buffer test simulation.
+ *
+ *	Revision 1.22  1998/10/21 13:23:52  mhaveman
+ *	-Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc).
+ *	-Changed calculation of hundrets of seconds.
+ *
+ *	Revision 1.20  1998/10/20 07:30:45  mhaveman
+ *	Made type changes to unsigned integer where possible.
+ *
+ *	Revision 1.19  1998/10/19 10:51:30  mhaveman
+ *	-Made Bug fixes after simulation run
+ *	-Renamed RlmtMAC... to RlmtPort...
+ *	-Marked workarounds with Errata comments
+ *
+ *	Revision 1.18  1998/10/14 07:50:08  mhaveman
+ *	-For OID_SKGE_LINK_STATUS the link down detection has moved from RLMT
+ *	 to HWACCESS.
+ *	-Provided all MEMCPY/MEMSET macros with (char *) pointers, because
+ *	 Solaris throwed warnings when mapping to bcopy/bset.
+ *
+ *	Revision 1.17  1998/10/13 07:42:01  mhaveman
+ *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA
+ *	-Removed old cvs history entries
+ *	-Renamed MacNumber to PortNumber
+ *
+ *	Revision 1.16  1998/10/07 10:52:49  mhaveman
+ *	-Inserted handling of some OID_GEN_ Ids for windows
+ *	-Fixed problem with 803.2 statistic.
+ *
+ *	Revision 1.15  1998/10/01 09:16:29  mhaveman
+ *	Added Debug messages for function call and UpdateFlag tracing.
+ *
+ *	Revision 1.14  1998/09/30 13:39:09  mhaveman
+ *	-Reduced namings of 'MAC' by replacing them with 'PORT'.
+ *	-Completed counting of OID_SKGE_RX_HW_ERROR_CTS,
+ *       OID_SKGE_TX_HW_ERROR_CTS,
+ *	 OID_SKGE_IN_ERRORS_CTS, and OID_SKGE_OUT_ERROR_CTS.
+ *	-SET check for RlmtMode
+ *
+ *	Revision 1.13  1998/09/28 13:13:08  mhaveman
+ *	Hide strcmp, strlen, and strncpy behind macros SK_STRCMP, SK_STRLEN,
+ *	and SK_STRNCPY. (Same reasons as for mem.. and MEM..)
+ *
+ *	Revision 1.12  1998/09/16 08:18:36  cgoos
+ *	Fix: XM_INxx and XM_OUTxx called with different parameter order:
+ *      sometimes IoC,Mac,...  sometimes Mac,IoC,... Now always first variant.
+ *	Fix: inserted "Pnmi." into some pAC->pDriverDescription / Version.
+ *	Change: memset, memcpy to makros SK_MEMSET, SK_MEMCPY
+ *
+ *	Revision 1.11  1998/09/04 17:01:45  mhaveman
+ *	Added SyncCounter as macro and OID_SKGE_.._NO_DESCR_CTS to
+ *	OID_SKGE_RX_NO_BUF_CTS.
+ *
+ *	Revision 1.10  1998/09/04 14:35:35  mhaveman
+ *	Added macro counters, that are counted by driver.
+ *
+ ****************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgepnmi.c,v 1.102 2002/12/16 14:03:24 tschilli Exp $"
+	" (C) SysKonnect.";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/xmac_ii.h"
+#include "h/skdebug.h"
+#include "h/skqueue.h"
+#include "h/skgepnmi.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skdrv2nd.h"
+#include "h/skgepnm2.h"
+#ifdef SK_POWER_MGMT
+#include "h/skgepmgt.h"
+#endif
+/* defines *******************************************************************/
+
+#ifndef DEBUG
+#define PNMI_STATIC	static
+#else	/* DEBUG */
+#define PNMI_STATIC
+#endif /* DEBUG */
+
+/*
+ * Public Function prototypes
+ */
+int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
+int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
+
+
+/*
+ * Private Function prototypes
+ */
+
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+	unsigned int PhysPortIndex, unsigned int StatIndex);
+PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
+	unsigned int StatIndex, SK_U32 NetIndex);
+PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
+	unsigned int *pEntries);
+PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+	unsigned int KeyArrLen, unsigned int *pKeyNo);
+PNMI_STATIC int LookupId(SK_U32 Id);
+PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+	unsigned int LastMac);
+PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int PortIndex);
+PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int SensorIndex);
+PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
+	unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+#include "skgemib.c"
+
+/* global variables **********************************************************/
+
+/*
+ * Overflow status register bit table and corresponding counter
+ * dependent on MAC type - the number relates to the size of overflow
+ * mask returned by the pFnMacOverflow function
+ */
+PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
+/* Bit0  */	{ SK_PNMI_HTX, 				SK_PNMI_HTX_UNICAST},
+/* Bit1  */	{ SK_PNMI_HTX_OCTETHIGH, 	SK_PNMI_HTX_BROADCAST},
+/* Bit2  */	{ SK_PNMI_HTX_OCTETLOW, 	SK_PNMI_HTX_PMACC},
+/* Bit3  */	{ SK_PNMI_HTX_BROADCAST, 	SK_PNMI_HTX_MULTICAST},
+/* Bit4  */	{ SK_PNMI_HTX_MULTICAST, 	SK_PNMI_HTX_OCTETLOW},
+/* Bit5  */	{ SK_PNMI_HTX_UNICAST, 		SK_PNMI_HTX_OCTETHIGH},
+/* Bit6  */	{ SK_PNMI_HTX_LONGFRAMES, 	SK_PNMI_HTX_64},
+/* Bit7  */	{ SK_PNMI_HTX_BURST, 		SK_PNMI_HTX_127},
+/* Bit8  */	{ SK_PNMI_HTX_PMACC, 		SK_PNMI_HTX_255},
+/* Bit9  */	{ SK_PNMI_HTX_MACC, 		SK_PNMI_HTX_511},
+/* Bit10 */	{ SK_PNMI_HTX_SINGLE_COL, 	SK_PNMI_HTX_1023},
+/* Bit11 */	{ SK_PNMI_HTX_MULTI_COL, 	SK_PNMI_HTX_MAX},
+/* Bit12 */	{ SK_PNMI_HTX_EXCESS_COL, 	SK_PNMI_HTX_LONGFRAMES},
+/* Bit13 */	{ SK_PNMI_HTX_LATE_COL, 	SK_PNMI_HTX_RESERVED},
+/* Bit14 */	{ SK_PNMI_HTX_DEFFERAL, 	SK_PNMI_HTX_COL},
+/* Bit15 */	{ SK_PNMI_HTX_EXCESS_DEF, 	SK_PNMI_HTX_LATE_COL},
+/* Bit16 */	{ SK_PNMI_HTX_UNDERRUN, 	SK_PNMI_HTX_EXCESS_COL},
+/* Bit17 */	{ SK_PNMI_HTX_CARRIER, 		SK_PNMI_HTX_MULTI_COL},
+/* Bit18 */	{ SK_PNMI_HTX_UTILUNDER, 	SK_PNMI_HTX_SINGLE_COL},
+/* Bit19 */	{ SK_PNMI_HTX_UTILOVER, 	SK_PNMI_HTX_UNDERRUN},
+/* Bit20 */	{ SK_PNMI_HTX_64, 			SK_PNMI_HTX_RESERVED},
+/* Bit21 */	{ SK_PNMI_HTX_127, 			SK_PNMI_HTX_RESERVED},
+/* Bit22 */	{ SK_PNMI_HTX_255, 			SK_PNMI_HTX_RESERVED},
+/* Bit23 */	{ SK_PNMI_HTX_511, 			SK_PNMI_HTX_RESERVED},
+/* Bit24 */	{ SK_PNMI_HTX_1023, 		SK_PNMI_HTX_RESERVED},
+/* Bit25 */	{ SK_PNMI_HTX_MAX, 			SK_PNMI_HTX_RESERVED},
+/* Bit26 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit27 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit28 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit29 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit30 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit31 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit32 */	{ SK_PNMI_HRX, 				SK_PNMI_HRX_UNICAST},
+/* Bit33 */	{ SK_PNMI_HRX_OCTETHIGH, 	SK_PNMI_HRX_BROADCAST},
+/* Bit34 */	{ SK_PNMI_HRX_OCTETLOW, 	SK_PNMI_HRX_PMACC},
+/* Bit35 */	{ SK_PNMI_HRX_BROADCAST, 	SK_PNMI_HRX_MULTICAST},
+/* Bit36 */	{ SK_PNMI_HRX_MULTICAST, 	SK_PNMI_HRX_FCS},
+/* Bit37 */	{ SK_PNMI_HRX_UNICAST, 		SK_PNMI_HRX_RESERVED},
+/* Bit38 */	{ SK_PNMI_HRX_PMACC, 		SK_PNMI_HRX_OCTETLOW},
+/* Bit39 */	{ SK_PNMI_HRX_MACC, 		SK_PNMI_HRX_OCTETHIGH},
+/* Bit40 */	{ SK_PNMI_HRX_PMACC_ERR, 	SK_PNMI_HRX_BADOCTETLOW},
+/* Bit41 */	{ SK_PNMI_HRX_MACC_UNKWN,	SK_PNMI_HRX_BADOCTETHIGH},
+/* Bit42 */	{ SK_PNMI_HRX_BURST, 		SK_PNMI_HRX_UNDERSIZE},
+/* Bit43 */	{ SK_PNMI_HRX_MISSED, 		SK_PNMI_HRX_RUNT},
+/* Bit44 */	{ SK_PNMI_HRX_FRAMING, 		SK_PNMI_HRX_64},
+/* Bit45 */	{ SK_PNMI_HRX_OVERFLOW, 	SK_PNMI_HRX_127},
+/* Bit46 */	{ SK_PNMI_HRX_JABBER, 		SK_PNMI_HRX_255},
+/* Bit47 */	{ SK_PNMI_HRX_CARRIER, 		SK_PNMI_HRX_511},
+/* Bit48 */	{ SK_PNMI_HRX_IRLENGTH, 	SK_PNMI_HRX_1023},
+/* Bit49 */	{ SK_PNMI_HRX_SYMBOL, 		SK_PNMI_HRX_MAX},
+/* Bit50 */	{ SK_PNMI_HRX_SHORTS, 		SK_PNMI_HRX_LONGFRAMES},
+/* Bit51 */	{ SK_PNMI_HRX_RUNT, 		SK_PNMI_HRX_TOO_LONG},
+/* Bit52 */	{ SK_PNMI_HRX_TOO_LONG, 	SK_PNMI_HRX_JABBER},
+/* Bit53 */	{ SK_PNMI_HRX_FCS, 			SK_PNMI_HRX_RESERVED},
+/* Bit54 */	{ SK_PNMI_HRX_RESERVED, 	SK_PNMI_HRX_OVERFLOW},
+/* Bit55 */	{ SK_PNMI_HRX_CEXT, 		SK_PNMI_HRX_RESERVED},
+/* Bit56 */	{ SK_PNMI_HRX_UTILUNDER, 	SK_PNMI_HRX_RESERVED},
+/* Bit57 */	{ SK_PNMI_HRX_UTILOVER, 	SK_PNMI_HRX_RESERVED},
+/* Bit58 */	{ SK_PNMI_HRX_64, 			SK_PNMI_HRX_RESERVED},
+/* Bit59 */	{ SK_PNMI_HRX_127, 			SK_PNMI_HRX_RESERVED},
+/* Bit60 */	{ SK_PNMI_HRX_255, 			SK_PNMI_HRX_RESERVED},
+/* Bit61 */	{ SK_PNMI_HRX_511, 			SK_PNMI_HRX_RESERVED},
+/* Bit62 */	{ SK_PNMI_HRX_1023, 		SK_PNMI_HRX_RESERVED},
+/* Bit63 */	{ SK_PNMI_HRX_MAX, 			SK_PNMI_HRX_RESERVED}
+};
+
+/*
+ * Table for hardware register saving on resets and port switches
+ */
+PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
+	/* SK_PNMI_HTX */
+	{{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_OCTETHIGH */
+	{{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HTX_OCTETLOW */
+	{{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HTX_BROADCAST */
+	{{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTICAST */
+	{{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_UNICAST */
+	{{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_BURST */
+	{{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_PMACC */
+	{{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HTX_MACC */
+	{{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_COL */
+	{{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_SINGLE_COL */
+	{{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTI_COL */
+	{{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_EXCESS_COL */
+	{{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_LATE_COL */
+	{{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_DEFFERAL */
+	{{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_EXCESS_DEF */
+	{{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UNDERRUN */
+	{{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
+	/* SK_PNMI_HTX_CARRIER */
+	{{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_64 */
+	{{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
+	/* SK_PNMI_HTX_127 */
+	{{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
+	/* SK_PNMI_HTX_255 */
+	{{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
+	/* SK_PNMI_HTX_511 */
+	{{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
+	/* SK_PNMI_HTX_1023 */
+	{{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HTX_MAX */
+	{{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HTX_LONGFRAMES  */
+	{{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HTX_SYNC */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_SYNC_OCTET */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX */
+	{{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_OCTETHIGH */
+	{{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_OCTETLOW */
+	{{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HRX_BADOCTETHIGH */
+	{{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_BADOCTETLOW */
+	{{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
+	/* SK_PNMI_HRX_BROADCAST */
+	{{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_MULTICAST */
+	{{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_UNICAST */
+	{{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_PMACC */
+	{{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HRX_MACC */
+	{{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_PMACC_ERR */
+	{{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MACC_UNKWN */
+	{{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_BURST */
+	{{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MISSED */
+	{{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_FRAMING */
+	{{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UNDERSIZE */
+	{{0, SK_FALSE},{GM_RXF_SHT, SK_TRUE}},
+	/* SK_PNMI_HRX_OVERFLOW */
+	{{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
+	/* SK_PNMI_HRX_JABBER */
+	{{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
+	/* SK_PNMI_HRX_CARRIER */
+	{{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_IRLENGTH */
+	{{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SYMBOL */
+	{{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SHORTS */
+	{{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_RUNT */
+	{{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
+	/* SK_PNMI_HRX_TOO_LONG */
+	{{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_FCS */
+	{{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_CEXT */
+	{{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_64 */
+	{{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
+	/* SK_PNMI_HRX_127 */
+	{{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
+	/* SK_PNMI_HRX_255 */
+	{{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
+	/* SK_PNMI_HRX_511 */
+	{{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
+	/* SK_PNMI_HRX_1023 */
+	{{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HRX_MAX */
+	{{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HRX_LONGFRAMES */
+	{{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HRX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}}
+};
+
+
+/*****************************************************************************
+ *
+ * Public functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * SkPnmiInit - Init function of PNMI
+ *
+ * Description:
+ *	SK_INIT_DATA: Initialises the data structures
+ *	SK_INIT_IO:   Resets the XMAC statistics, determines the device and
+ *	              connector type.
+ *	SK_INIT_RUN:  Starts a timer event for port switch per hour
+ *	              calculation.
+ *
+ * Returns:
+ *	Always 0
+ */
+int SkPnmiInit(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Level)		/* Initialization level */
+{
+	unsigned int	PortMax;	/* Number of ports */
+	unsigned int	PortIndex;	/* Current port index in loop */
+	SK_U16		Val16;		/* Multiple purpose 16 bit variable */
+	SK_U8		Val8;		/* Mulitple purpose 8 bit variable */
+	SK_EVPARA	EventParam;	/* Event struct for timer event */
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiInit: Called, level=%d\n", Level));
+
+	switch (Level) {
+
+	case SK_INIT_DATA:
+		SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
+		pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
+		pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
+		for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
+
+			pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+			pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+		}
+
+#ifdef SK_PNMI_CHECK
+		if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("CounterOffset struct size (%d) differs from"
+						"SK_PNMI_MAX_IDX (%d)\n",
+						SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
+			BRK;
+		}
+
+		if (SK_PNMI_MAX_IDX !=
+			(sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("StatAddr table size (%d) differs from "
+						"SK_PNMI_MAX_IDX (%d)\n",
+						(sizeof(StatAddr) /
+						 (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
+						 SK_PNMI_MAX_IDX));
+			BRK;
+		}
+#endif /* SK_PNMI_CHECK */
+		break;
+
+	case SK_INIT_IO:
+		/*
+		 * Reset MAC counters
+		 */
+		PortMax = pAC->GIni.GIMacsFound;
+
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+
+			pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
+		}
+
+		/* Initialize DSP variables for Vct() to 0xff => Never written! */
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+			pPrt = &pAC->GIni.GP[PortIndex];
+			pPrt->PCableLen =0xff;
+			pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
+			pVctBackupData->PCableLen = 0xff;
+		}
+
+		/*
+		 * Get pci bus speed
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_CLOCK) == 0) {
+
+			pAC->Pnmi.PciBusSpeed = 33;
+		}
+		else {
+			pAC->Pnmi.PciBusSpeed = 66;
+		}
+
+		/*
+		 * Get pci bus width
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_SLOT_SZ) == 0) {
+
+			pAC->Pnmi.PciBusWidth = 32;
+		}
+		else {
+			pAC->Pnmi.PciBusWidth = 64;
+		}
+
+		/*
+		 * Get chipset
+		 */
+		switch (pAC->GIni.GIChipId) {
+		case CHIP_ID_GENESIS:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
+			break;
+
+		case CHIP_ID_YUKON:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
+			break;
+
+		default:
+			break;
+		}
+
+		/*
+		 * Get PMD and DeviceType
+		 */
+		SK_IN8(IoC, B2_PMD_TYP, &Val8);
+		switch (Val8) {
+		case 'S':
+			pAC->Pnmi.PMD = 3;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020002;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020001;
+			}
+			break;
+
+		case 'L':
+			pAC->Pnmi.PMD = 2;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020004;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020003;
+			}
+			break;
+
+		case 'C':
+			pAC->Pnmi.PMD = 4;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020006;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020005;
+			}
+			break;
+
+		case 'T':
+			pAC->Pnmi.PMD = 5;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020008;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020007;
+			}
+			break;
+
+		default :
+			pAC->Pnmi.PMD = 1;
+			pAC->Pnmi.DeviceType = 0;
+			break;
+		}
+
+		/*
+		 * Get connector
+		 */
+		SK_IN8(IoC, B2_CONN_TYP, &Val8);
+		switch (Val8) {
+		case 'C':
+			pAC->Pnmi.Connector = 2;
+			break;
+
+		case 'D':
+			pAC->Pnmi.Connector = 3;
+			break;
+
+		case 'F':
+			pAC->Pnmi.Connector = 4;
+			break;
+
+		case 'J':
+			pAC->Pnmi.Connector = 5;
+			break;
+
+		case 'V':
+			pAC->Pnmi.Connector = 6;
+			break;
+
+		default:
+			pAC->Pnmi.Connector = 1;
+			break;
+		}
+		break;
+
+	case SK_INIT_RUN:
+		/*
+		 * Start timer for RLMT change counter
+		 */
+		SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	default:
+		break; /* Nothing todo */
+	}
+
+	return (0);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetVar - Retrieves the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. If the instance
+ *	-1 is passed, the values of all instances are returned in an
+ *	array of values.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+int SkPnmiGetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetVar - Presets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	If as instance a -1 is passed, an array of values is supposed and
+ *	all instance of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+int SkPnmiPreSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetVar - Sets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	If as instance a -1 is passed, an array of values is supposed and
+ *	all instance of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+int SkPnmiSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Runs through the IdTable, queries the single OIDs and stores the
+ *	returned data into the management database structure
+ *	SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
+ *	is stored in the IdTable. The return value of the function will also
+ *	be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+int SkPnmiGetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which will store the retrieved data */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	unsigned int	TmpLen;
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+    /*
+     * Check NetIndex
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
+	/* Update statistic */
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
+
+	if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
+		SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	/*
+	 * Increment semaphores to indicate that an update was
+	 * already done
+	 */
+	pAC->Pnmi.MacUpdatedFlag ++;
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Get vpd keys for instance calculation */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		pAC->Pnmi.RlmtUpdatedFlag --;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/* Retrieve values */
+	SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * For the VPD the instance is not an index number
+			 * but the key itself. Determin with the instance
+			 * counter the VPD key to be used.
+			 */
+			if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
+
+				SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
+			}
+			else {
+				Instance = (SK_U32)InstanceCnt;
+			}
+
+			TmpLen = *pLen - DstOffset;
+			Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
+				IdTable[TableIndex].Id, (char *)pBuf +
+				DstOffset, &TmpLen, Instance, TableIndex, NetIndex);
+
+			/*
+			 * An unknown instance error means that we reached
+			 * the last instance of that variable. Proceed with
+			 * the next OID in the table and ignore the return
+			 * code.
+			 */
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+		break;
+			}
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.MacUpdatedFlag --;
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (Ret);
+			}
+		}
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	*pLen = SK_PNMI_STRUCT_SIZE;
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	preset. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+int SkPnmiPreSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf,
+					pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The return value
+ *	of the function will also be stored in SK_PNMI_STRUCT_DATA if the
+ *	passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	set. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+int SkPnmiSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf,
+					pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiEvent - Event handler
+ *
+ * Description:
+ *	Handles the following events:
+ *	SK_PNMI_EVT_SIRQ_OVERFLOW     When a hardware counter overflows an
+ *	                              interrupt will be generated which is
+ *	                              first handled by SIRQ which generates a
+ *	                              this event. The event increments the
+ *	                              upper 32 bit of the 64 bit counter.
+ *	SK_PNMI_EVT_SEN_XXX           The event is generated by the I2C module
+ *	                              when a sensor reports a warning or
+ *	                              error. The event will store a trap
+ *	                              message in the trap buffer.
+ *	SK_PNMI_EVT_CHG_EST_TIMER     The timer event was initiated by this
+ *	                              module and is used to calculate the
+ *	                              port switches per hour.
+ *	SK_PNMI_EVT_CLEAR_COUNTER     The event clears all counters and
+ *	                              timestamps.
+ *	SK_PNMI_EVT_XMAC_RESET        The event is generated by the driver
+ *	                              before a hard reset of the XMAC is
+ *	                              performed. All counters will be saved
+ *	                              and added to the hardware counter
+ *	                              values after reset to grant continuous
+ *	                              counter values.
+ *	SK_PNMI_EVT_RLMT_PORT_UP      Generated by RLMT to notify that a port
+ *	                              went logically up. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
+ *	                              went logically down. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
+ *	                              spanning tree root bridges were
+ *	                              detected. A trap message will be stored
+ *	                              to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_DOWN  Notifies PNMI that an active port went
+ *	                              down. PNMI will not further add the
+ *	                              statistic values to the virtual port.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_UP    Notifies PNMI that a port went up and
+ *	                              is now an active port. PNMI will now
+ *	                              add the statistic data of this port to
+ *	                              the virtual port.
+ *	SK_PNMI_EVT_RLMT_SET_NETS     Notifies PNMI about the net mode. The first Parameter
+ *	                              contains the number of nets. 1 means single net, 2 means
+ *	                              dual net. The second Parameter is -1
+ *
+ * Returns:
+ *	Always 0
+ */
+int SkPnmiEvent(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Event,		/* Event-Id */
+SK_EVPARA Param)	/* Event dependent parameter */
+{
+	unsigned int	PhysPortIndex;
+	unsigned int	MaxNetNumber;
+	int			CounterIndex;
+	int			Ret;
+	SK_U16		MacStatus;
+	SK_U64		OverflowStatus;
+	SK_U64		Mask;
+	int			MacType;
+	SK_U64		Value;
+	SK_U32		Val32;
+	SK_U16		Register;
+	SK_EVPARA	EventParam;
+	SK_U64		NewestValue;
+	SK_U64		OldestValue;
+	SK_U64		Delta;
+	SK_PNMI_ESTIMATE *pEst;
+	SK_U32		NetIndex;
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		RetCode;
+	int		i;
+	SK_U32		CableLength;
+
+
+#ifdef DEBUG
+	if (Event != SK_PNMI_EVT_XMAC_RESET) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+			("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
+			(unsigned int)Event, (unsigned int)Param.Para64));
+	}
+#endif
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
+
+	MacType = pAC->GIni.GIMacType;
+
+	switch (Event) {
+
+	case SK_PNMI_EVT_SIRQ_OVERFLOW:
+		PhysPortIndex = (int)Param.Para32[0];
+		MacStatus = (SK_U16)Param.Para32[1];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
+				 " wrong, PhysPortIndex=0x%x\n",
+				PhysPortIndex));
+			return (0);
+		}
+#endif
+		OverflowStatus = 0;
+
+		/*
+		 * Check which source caused an overflow interrupt.
+		 */
+		if ((pAC->GIni.GIFunc.pFnMacOverflow(
+			 pAC, IoC, PhysPortIndex, MacStatus, &OverflowStatus) != 0) ||
+			(OverflowStatus == 0)) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+
+		/*
+		 * Check the overflow status register and increment
+		 * the upper dword of corresponding counter.
+		 */
+		for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
+			CounterIndex ++) {
+
+			Mask = (SK_U64)1 << CounterIndex;
+			if ((OverflowStatus & Mask) == 0) {
+
+				continue;
+			}
+
+			switch (StatOvrflwBit[CounterIndex][MacType]) {
+
+			case SK_PNMI_HTX_UTILUNDER:
+			case SK_PNMI_HTX_UTILOVER:
+				XM_IN16(IoC, PhysPortIndex, XM_TX_CMD,
+					&Register);
+				Register |= XM_TX_SAM_LINE;
+				XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD,
+					Register);
+				break;
+
+			case SK_PNMI_HRX_UTILUNDER:
+			case SK_PNMI_HRX_UTILOVER:
+				XM_IN16(IoC, PhysPortIndex, XM_RX_CMD,
+					&Register);
+				Register |= XM_RX_SAM_LINE;
+				XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD,
+					Register);
+				break;
+
+			case SK_PNMI_HTX_OCTETHIGH:
+			case SK_PNMI_HTX_OCTETLOW:
+			case SK_PNMI_HTX_RESERVED:
+			case SK_PNMI_HRX_OCTETHIGH:
+			case SK_PNMI_HRX_OCTETLOW:
+			case SK_PNMI_HRX_IRLENGTH:
+			case SK_PNMI_HRX_RESERVED:
+
+			/*
+			 * the following counters aren't be handled (id > 63)
+			 */
+			case SK_PNMI_HTX_SYNC:
+			case SK_PNMI_HTX_SYNC_OCTET:
+				break;
+
+			case SK_PNMI_HRX_LONGFRAMES:
+				if (MacType == SK_MAC_GMAC) {
+					pAC->Pnmi.Port[PhysPortIndex].
+						CounterHigh[CounterIndex] ++;
+				}
+				break;
+
+			default:
+				pAC->Pnmi.Port[PhysPortIndex].
+					CounterHigh[CounterIndex] ++;
+			}
+		}
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR:SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_ERR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_ERR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_CHG_EST_TIMER:
+		/*
+		 * Calculate port switch average on a per hour basis
+		 *   Time interval for check       : 28125 ms
+		 *   Number of values for average  : 8
+		 *
+		 * Be careful in changing these values, on change check
+		 *   - typedef of SK_PNMI_ESTIMATE (Size of EstValue
+		 *     array one less than value number)
+		 *   - Timer initilization SkTimerStart() in SkPnmiInit
+		 *   - Delta value below must be multiplicated with
+		 *     power of 2
+		 *
+		 */
+		pEst = &pAC->Pnmi.RlmtChangeEstimate;
+		CounterIndex = pEst->EstValueIndex + 1;
+		if (CounterIndex == 7) {
+
+			CounterIndex = 0;
+		}
+		pEst->EstValueIndex = CounterIndex;
+
+		NewestValue = pAC->Pnmi.RlmtChangeCts;
+		OldestValue = pEst->EstValue[CounterIndex];
+		pEst->EstValue[CounterIndex] = NewestValue;
+
+		/*
+		 * Calculate average. Delta stores the number of
+		 * port switches per 28125 * 8 = 225000 ms
+		 */
+		if (NewestValue >= OldestValue) {
+
+			Delta = NewestValue - OldestValue;
+		}
+		else {
+			/* Overflow situation */
+			Delta = (SK_U64)(0 - OldestValue) + NewestValue;
+		}
+
+		/*
+		 * Extrapolate delta to port switches per hour.
+		 *     Estimate = Delta * (3600000 / 225000)
+		 *              = Delta * 16
+		 *              = Delta << 4
+		 */
+		pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;
+
+		/*
+		 * Check if threshold is exceeded. If the threshold is
+		 * permanently exceeded every 28125 ms an event will be
+		 * generated to remind the user of this condition.
+		 */
+		if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
+			(pAC->Pnmi.RlmtChangeEstimate.Estimate >=
+			pAC->Pnmi.RlmtChangeThreshold)) {
+
+			QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
+			(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		}
+
+		SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	case SK_PNMI_EVT_CLEAR_COUNTER:
+		/*
+		 *  Param.Para32[0] contains the NetIndex (0 ..1).
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+		NetIndex = (SK_U32)Param.Para32[0];
+
+#ifdef DEBUG
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
+				NetIndex));
+
+			return (0);
+		}
+#endif
+
+		/*
+		 * Set all counters and timestamps to zero
+		 */
+		ResetCounter(pAC, IoC, NetIndex); /* the according NetIndex is required
+												as a Parameter of the Event */
+		break;
+
+	case SK_PNMI_EVT_XMAC_RESET:
+		/*
+		 * To grant continuous counter values store the current
+		 * XMAC statistic values to the entries 1..n of the
+		 * CounterOffset array. XMAC Errata #2
+		 */
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		PhysPortIndex = (unsigned int)Param.Para64;
+
+		/*
+		 * Update XMAC statistic to get fresh values
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		/*
+		 * Increment semaphore to indicate that an update was
+		 * already done
+		 */
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			pAC->Pnmi.Port[PhysPortIndex].
+				CounterOffset[CounterIndex] = GetPhysStatVal(
+				pAC, IoC, PhysPortIndex, CounterIndex);
+			pAC->Pnmi.Port[PhysPortIndex].
+				CounterHigh[CounterIndex] = 0;
+		}
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_PORT_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
+		 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/* Bugfix for XMAC errata (#10620)*/
+		if (pAC->GIni.GIMacType == SK_MAC_XMAC){
+
+			/* Add incremental difference to offset (#10620)*/
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+
+			Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+			pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
+				Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
+		}
+
+		/* Tell VctStatus() that a link was up meanwhile. */
+		pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;
+		break;
+
+    case SK_PNMI_EVT_RLMT_PORT_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
+		 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/* Bugfix #10620 - get zero level for incremental difference */
+		if ((pAC->GIni.GIMacType == SK_MAC_XMAC)) {
+
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+			pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark =
+				(((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+		}
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
+#endif
+		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
+		 * Nothing to do if port is already inactive
+		 */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was already
+		 * done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. The virtual port consists of all currently
+		 * active ports. The port down event indicates that a port is removed
+		 * from the virtual port. Therefore add the counter value of the removed
+		 * port to the CounterOffset for the virtual port to grant the same
+		 * counter value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
+		}
+
+		/*
+		 * Set port to inactive
+		 */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
+#endif
+		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
+		 * Nothing to do if port is already active
+		 */
+		if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Statistic maintenance
+		 */
+		pAC->Pnmi.RlmtChangeCts ++;
+		pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtNewMacTrap(pAC, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/*
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. A new port is added to the virtual port.
+		 * Therefore substract the counter value of the new port from the
+		 * CounterOffset for the virtual port to grant the same value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
+		}
+
+		/*
+		 * Set port to active
+		 */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_SEGMENTATION:
+		/*
+		 * Para.Para32[0] contains the NetIndex.
+		 */
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+    case SK_PNMI_EVT_RLMT_SET_NETS:
+		/*
+		 *  Param.Para32[0] contains the number of Nets.
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+	    /*
+	 * Check number of nets
+		 */
+		MaxNetNumber = pAC->GIni.GIMacsFound;
+		if (((unsigned int)Param.Para32[0] < 1)
+			|| ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
+			return (SK_PNMI_ERR_UNKNOWN_NET);
+		}
+
+	if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
+		pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+	}
+	else { /* dual net mode */
+		pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
+	}
+	break;
+
+    case SK_PNMI_EVT_VCT_RESET:
+	PhysPortIndex = Param.Para32[0];
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+
+	if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+		RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+		if (RetCode == 2) {
+			/*
+			 * VCT test is still running.
+			 * Start VCT timer counter again.
+			 */
+			SK_MEMSET((char *) &Param, 0, sizeof(Param));
+			Param.Para32[0] = PhysPortIndex;
+			Param.Para32[1] = -1;
+			SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+				4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
+			break;
+		}
+		pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+		pAC->Pnmi.VctStatus[PhysPortIndex] |=
+			(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+
+		/* Copy results for later use to PNMI struct. */
+		for (i = 0; i < 4; i++)  {
+			if (pPrt->PMdiPairLen[i] > 35) {
+				CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+			}
+			else {
+				CableLength = 0;
+			}
+			pVctBackupData->PMdiPairLen[i] = CableLength;
+			pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+		}
+
+		Param.Para32[0] = PhysPortIndex;
+		Param.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
+		SkEventDispatcher(pAC, IoC);
+	}
+
+	break;
+
+	default:
+		break;
+	}
+
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+	return (0);
+}
+
+
+/******************************************************************************
+ *
+ * Private functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * PnmiVar - Gets, presets, and sets single OIDs
+ *
+ * Description:
+ *	Looks up the requested OID, calls the corresponding handler
+ *	function, and passes the parameters with the get, preset, or
+ *	set command. The function is called by SkGePnmiGetVar,
+ *	SkGePnmiPreSetVar, or SkGePnmiSetVar.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. For details have a look to the description of the
+ *	calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	TableIndex;
+	int		Ret;
+
+
+	if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_OID);
+	}
+
+    /*
+     * Check NetIndex
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On call");
+
+	Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
+		Instance, TableIndex, NetIndex);
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On return");
+
+	return (Ret);
+}
+
+/*****************************************************************************
+ *
+ * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
+ *	checks which OIDs are able to set, and calls the handler function of
+ *	the OID to perform the set. The return value of the function will
+ *	also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
+ *	by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int  Action,		/* Set action to be performed */
+char *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	Len;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	SK_U32		Id;
+
+
+	/* Check if the passed buffer has the right size */
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		/* Check if we can return the error within the buffer */
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+    /*
+     * Check NetIndex
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
+
+	/*
+	 * Update the values of RLMT and SIRQ and increment semaphores to
+	 * indicate that an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Preset/Set values */
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+		if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
+			(IdTable[TableIndex].Access != SK_PNMI_WO)) {
+
+			continue;
+		}
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+		Id = IdTable[TableIndex].Id;
+
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * Because VPD multiple instance variables are
+			 * not setable we do not need to evaluate VPD
+			 * instances. Have a look to VPD instance
+			 * calculation in SkPnmiGetStruct().
+			 */
+			Instance = (SK_U32)InstanceCnt;
+
+			/*
+			 * Evaluate needed buffer length
+			 */
+			Len = 0;
+			Ret = IdTable[TableIndex].Func(pAC, IoC,
+				SK_PNMI_GET, IdTable[TableIndex].Id,
+				NULL, &Len, Instance, TableIndex, NetIndex);
+
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+				break;
+			}
+			if (Ret != SK_PNMI_ERR_TOO_SHORT) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf,
+					SK_PNMI_ERR_GENERAL, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if (Id == OID_SKGE_VPD_ACTION) {
+
+				switch (*(pBuf + DstOffset)) {
+
+				case SK_PNMI_VPD_CREATE:
+					Len = 3 + *(pBuf + DstOffset + 3);
+					break;
+
+				case SK_PNMI_VPD_DELETE:
+					Len = 3;
+					break;
+
+				default:
+					Len = 1;
+					break;
+				}
+			}
+
+			/* Call the OID handler function */
+			Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
+				IdTable[TableIndex].Id, pBuf + DstOffset,
+				&Len, Instance, TableIndex, NetIndex);
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
+					DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+		}
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * LookupId - Lookup an OID in the IdTable
+ *
+ * Description:
+ *	Scans the IdTable to find the table entry of an OID.
+ *
+ * Returns:
+ *	The table index or -1 if not found.
+ */
+PNMI_STATIC int LookupId(
+SK_U32 Id)		/* Object identifier to be searched */
+{
+	int i;
+
+	for (i = 0; i < ID_TABLE_SIZE; i++) {
+
+		if (IdTable[i].Id == Id) {
+
+			return i;
+		}
+	}
+
+	return (-1);
+}
+
+/*****************************************************************************
+ *
+ * OidStruct - Handler of OID_SKGE_ALL_DATA
+ *
+ * Description:
+ *	This OID performs a Get/Preset/SetStruct call and returns all data
+ *	in a SK_PNMI_STRUCT_DATA structure.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int OidStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	if (Id != OID_SKGE_ALL_DATA) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
+			SK_PNMI_ERR003MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	switch (Action) {
+
+	case SK_PNMI_GET:
+		return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+	case SK_PNMI_PRESET:
+		return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+	case SK_PNMI_SET:
+		return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+	}
+
+	SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
+
+	*pLen = 0;
+	return (SK_PNMI_ERR_GENERAL);
+}
+
+/*****************************************************************************
+ *
+ * Perform - OID handler of OID_SKGE_ACTION
+ *
+ * Description:
+ *	None.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Perform(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int	Ret;
+	SK_U32	ActionOp;
+
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	if (*pLen < sizeof(SK_U32)) {
+
+		*pLen = sizeof(SK_U32);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/* Check if a get should be performed */
+	if (Action == SK_PNMI_GET) {
+
+		/* A get is easy. We always return the same value */
+		ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
+		SK_PNMI_STORE_U32(pBuf, ActionOp);
+		*pLen = sizeof(SK_U32);
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Continue with PRESET/SET action */
+	if (*pLen > sizeof(SK_U32)) {
+
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* Check if the command is a known one */
+	SK_PNMI_READ_U32(pBuf, ActionOp);
+	if (*pLen > sizeof(SK_U32) ||
+		(ActionOp != SK_PNMI_ACT_IDLE &&
+		ActionOp != SK_PNMI_ACT_RESET &&
+		ActionOp != SK_PNMI_ACT_SELFTEST &&
+		ActionOp != SK_PNMI_ACT_RESETCNT)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* A preset ends here */
+	if (Action == SK_PNMI_PRESET) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	switch (ActionOp) {
+
+	case SK_PNMI_ACT_IDLE:
+		/* Nothing to do */
+		break;
+
+	case SK_PNMI_ACT_RESET:
+		/*
+		 * Perform a driver reset or something that comes near
+		 * to this.
+		 */
+		Ret = SK_DRIVER_RESET(pAC, IoC);
+		if (Ret != 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
+				SK_PNMI_ERR005MSG);
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		break;
+
+	case SK_PNMI_ACT_SELFTEST:
+		/*
+		 * Perform a driver selftest or something similar to this.
+		 * Currently this feature is not used and will probably
+		 * implemented in another way.
+		 */
+		Ret = SK_DRIVER_SELFTEST(pAC, IoC);
+		pAC->Pnmi.TestResult = Ret;
+		break;
+
+	case SK_PNMI_ACT_RESETCNT:
+		/* Set all counters and timestamps to zero */
+		ResetCounter(pAC, IoC, NetIndex);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
+			SK_PNMI_ERR006MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the virtual port (logical
+ *	index 0). Only special OIDs of NDIS are handled which consist
+ *	of a 32 bit instead of a 64 bit value. The OIDs are public
+ *	because perhaps some other platform can use them too.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Mac8023Stat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex,	/* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int     Ret;
+	SK_U64  StatVal;
+	SK_U32  StatVal32;
+	SK_BOOL Is64BitReq = SK_FALSE;
+
+	/*
+	 * Only the active Mac is returned
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action type
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+	case OID_802_3_CURRENT_ADDRESS:
+		if (*pLen < sizeof(SK_MAC_ADDR)) {
+
+			*pLen = sizeof(SK_MAC_ADDR);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+#ifndef SK_NDIS_64BIT_CTR
+		if (*pLen < sizeof(SK_U32)) {
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+#else /* SK_NDIS_64BIT_CTR */
+
+		/*
+		 * for compatibility, at least 32bit are required for oid
+		 */
+		if (*pLen < sizeof(SK_U32)) {
+			/*
+			* but indicate handling for 64bit values,
+			* if insufficient space is provided
+			*/
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+		break;
+	}
+
+	/*
+	 * Update all statistics, because we retrieve virtual MAC, which
+	 * consists of multiple physical statistics and increment semaphore
+	 * to indicate that an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+	if ( Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/*
+	 * Get value (MAC Index 0 identifies the virtual MAC)
+	 */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	case OID_802_3_CURRENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	default:
+		StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			StatVal32 = (SK_U32)StatVal;
+			SK_PNMI_STORE_U32(pBuf, StatVal32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, StatVal);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
+ *
+ * Description:
+ *	Retrieves the XMAC statistic data.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int MacPrivateStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortMax;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int				Ret;
+	SK_U64			StatVal;
+
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Update XMAC statistic and increment semaphore to indicate that
+	 * an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/*
+	 * Get value
+	 */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_TX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_RX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+		case OID_SKGE_STAT_RX:
+		case OID_SKGE_STAT_TX:
+			switch (pAC->GIni.GIMacType) {
+			case SK_MAC_XMAC:
+				StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+					IdTable[TableIndex].Param, NetIndex);
+				break;
+
+			case SK_MAC_GMAC:
+				if (Id == OID_SKGE_STAT_TX) {
+
+					StatVal =
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_BROADCAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_MULTICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_UNICAST, NetIndex);
+				}
+				else {
+					StatVal =
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_BROADCAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_MULTICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_UNICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_UNDERSIZE, NetIndex);
+				}
+				break;
+
+			default:
+				StatVal = 0;
+				break;
+			}
+
+			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+			break;
+
+		default:
+			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+				IdTable[TableIndex].Param, NetIndex);
+			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+			break;
+		}
+
+		Offset += sizeof(SK_U64);
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
+ *
+ * Description:
+ *	Get/Presets/Sets the current and factory MAC address. The MAC
+ *	address of the virtual port, which is reported to the OS, may
+ *	not be changed, but the physical ones. A set to the virtual port
+ *	will be ignored. No error should be reported because otherwise
+ *	a multiple instance set (-1) would always fail.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Addr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int		Ret;
+	unsigned int	LogPortMax;
+	unsigned int	PhysPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform Action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		*/
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * Get value
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_PHYS_CUR_ADDR:
+				if (LogPortIndex == 0) {
+					CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			case OID_SKGE_PHYS_FAC_ADDR:
+				if (LogPortIndex == 0) {
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Net[NetIndex].PermanentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
+					SK_PNMI_ERR008MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+
+		*pLen = Offset;
+	}
+	else {
+		/*
+		 * The logical MAC address may not be changed only
+		 * the physical ones
+		 */
+		if (Id == OID_SKGE_PHYS_FAC_ADDR) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/*
+		 * Only the current address may be changed
+		 */
+		if (Id != OID_SKGE_PHYS_CUR_ADDR) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
+				SK_PNMI_ERR009MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Check length
+		*/
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen > (Limit - LogPortIndex) * 6) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+
+		/*
+		 * Check Action
+		 */
+		if (Action == SK_PNMI_PRESET) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_OK);
+		}
+
+		/*
+		 * Set OID_SKGE_MAC_CUR_ADDR
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {
+
+			/*
+			 * A set to virtual port and set of broadcast
+			 * address will be ignored
+			 */
+			if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
+				"\xff\xff\xff\xff\xff\xff", 6) == 0) {
+
+				continue;
+			}
+
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
+				LogPortIndex);
+
+			Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
+				(SK_MAC_ADDR *)(pBuf + Offset),
+				(LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
+				SK_ADDR_PHYSICAL_ADDRESS));
+			if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {
+
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the CSUM module. The CSUM data
+ *	structure must be available in the SK_AC even if the CSUM module
+ *	is not included, because PNMI reads the statistic data from the
+ *	CSUM part of SK_AC directly.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int CsumStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+	SK_U64		StatVal;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if (Instance != (SK_U32)(-1)) {
+
+		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		Index = (unsigned int)Instance - 1;
+		Limit = Index + 1;
+	}
+	else {
+		Index = 0;
+		Limit = SKCS_NUM_PROTOCOLS;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - Index) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Get value
+	 */
+	for (; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_CHKSM_RX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_ERR_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
+				SK_PNMI_ERR010MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+		Offset += sizeof(SK_U64);
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the I2C module, which handles
+ *	the temperature and voltage sensors.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int SensorStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	i;
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Len;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance -1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = (unsigned int) pAC->I2c.MaxSens;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	switch (Id) {
+
+	case OID_SKGE_SENSOR_VALUE:
+	case OID_SKGE_SENSOR_WAR_THRES_LOW:
+	case OID_SKGE_SENSOR_WAR_THRES_UPP:
+	case OID_SKGE_SENSOR_ERR_THRES_LOW:
+	case OID_SKGE_SENSOR_ERR_THRES_UPP:
+		if (*pLen < (Limit - Index) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_DESCR:
+		for (Offset = 0, i = Index; i < Limit; i ++) {
+
+			Len = (unsigned int)
+				SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
+			if (Len >= SK_PNMI_STRINGLEN2) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
+					SK_PNMI_ERR011MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			Offset += Len;
+		}
+		if (*pLen < Offset) {
+
+			*pLen = Offset;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_INDEX:
+	case OID_SKGE_SENSOR_TYPE:
+	case OID_SKGE_SENSOR_STATUS:
+		if (*pLen < Limit - Index) {
+
+			*pLen = Limit - Index;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_WAR_CTS:
+	case OID_SKGE_SENSOR_WAR_TIME:
+	case OID_SKGE_SENSOR_ERR_CTS:
+	case OID_SKGE_SENSOR_ERR_TIME:
+		if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
+			SK_PNMI_ERR012MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Get value
+	 */
+	for (Offset = 0; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_SENSOR_INDEX:
+			*(pBuf + Offset) = (char)Index;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_DESCR:
+			Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
+			SK_MEMCPY(pBuf + Offset + 1,
+				pAC->I2c.SenTable[Index].SenDesc, Len);
+			*(pBuf + Offset) = (char)Len;
+			Offset += Len + 1;
+			break;
+
+		case OID_SKGE_SENSOR_TYPE:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenType;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_VALUE:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_UPP:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreErrLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_UPP:
+			Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_STATUS:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenErrFlag;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenErrCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegWarnTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegErrTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("SensorStat: Unknown OID should be handled before"));
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Vpd - OID handler function of OID_SKGE_VPD_XXX
+ *
+ * Description:
+ *	Get/preset/set of VPD data. As instance the name of a VPD key
+ *	can be passed. The Instance parameter is a SK_U32 and can be
+ *	used as a string buffer for the VPD key, because their maximum
+ *	length is 4 byte.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Vpd(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_VPD_STATUS	*pVpdStatus;
+	unsigned int	BufLen;
+	char		Buf[256];
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+	char		KeyStr[SK_PNMI_VPD_KEY_SIZE];
+	unsigned int	KeyNo;
+	unsigned int	Offset;
+	unsigned int	Index;
+	unsigned int	FirstIndex;
+	unsigned int	LastIndex;
+	unsigned int	Len;
+	int		Ret;
+	SK_U32		Val32;
+
+	/*
+	 * Get array of all currently stored VPD keys
+	 */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr),
+		&KeyNo);
+	if (Ret != SK_PNMI_ERR_OK) {
+		*pLen = 0;
+		return (Ret);
+	}
+
+	/*
+	 * If instance is not -1, try to find the requested VPD key for
+	 * the multiple instance variables. The other OIDs as for example
+	 * OID VPD_ACTION are single instance variables and must be
+	 * handled separatly.
+	 */
+	FirstIndex = 0;
+	LastIndex = KeyNo;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
+			Id == OID_SKGE_VPD_ACCESS) {
+
+			SK_STRNCPY(KeyStr, (char *)&Instance, 4);
+			KeyStr[4] = 0;
+
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+					FirstIndex = Index;
+					LastIndex = Index+1;
+					break;
+				}
+			}
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_UNKNOWN_INST);
+			}
+		}
+		else if (Instance != 1) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+	}
+
+	/*
+	 * Get value, if a query should be performed
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		switch (Id) {
+
+		case OID_SKGE_VPD_FREE_BYTES:
+			/* Check length of buffer */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Get number of free bytes */
+			pVpdStatus = VpdStat(pAC, IoC);
+			if (pVpdStatus == NULL) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
+					SK_PNMI_ERR017MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
+					SK_PNMI_ERR018MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_LIST:
+			/* Check length */
+			for (Len = 0, Index = 0; Index < KeyNo; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/* Get value */
+			*(pBuf) = (char)Len - 1;
+			for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+				SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);
+
+				Offset += Len;
+
+				if (Index < KeyNo - 1) {
+
+					*(pBuf + Offset) = ' ';
+					Offset ++;
+				}
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_NUMBER:
+			/* Check length */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			Val32 = (SK_U32)KeyNo;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_KEY:
+			/* Check buffer length, if it is large enough */
+			for (Len = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the key to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+
+				*(pBuf + Offset) = (char)Len;
+				SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
+					Len);
+				Offset += Len + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_VALUE:
+			/* Check the buffer length if it is large enough */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR021,
+						SK_PNMI_ERR021MSG);
+
+					return (SK_PNMI_ERR_GENERAL);
+				}
+				Offset += BufLen + 1;
+			}
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the value to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR022,
+						SK_PNMI_ERR022MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+
+				*(pBuf + Offset) = (char)BufLen;
+				SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
+				Offset += BufLen + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACCESS:
+			if (*pLen < LastIndex - FirstIndex) {
+
+				*pLen = LastIndex - FirstIndex;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				if (VpdMayWrite(KeyArr[Index])) {
+
+					*(pBuf + Offset) = SK_PNMI_VPD_RW;
+				}
+				else {
+					*(pBuf + Offset) = SK_PNMI_VPD_RO;
+				}
+				Offset ++;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACTION:
+			Offset = LastIndex - FirstIndex;
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			SK_MEMSET(pBuf, 0, Offset);
+			*pLen = Offset;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
+				SK_PNMI_ERR023MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+	else {
+		/* The only OID which can be set is VPD_ACTION */
+		if (Id != OID_SKGE_VPD_ACTION) {
+
+			if (Id == OID_SKGE_VPD_FREE_BYTES ||
+				Id == OID_SKGE_VPD_ENTRIES_LIST ||
+				Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
+				Id == OID_SKGE_VPD_KEY ||
+				Id == OID_SKGE_VPD_VALUE ||
+				Id == OID_SKGE_VPD_ACCESS) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_READ_ONLY);
+			}
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
+				SK_PNMI_ERR024MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * From this point we handle VPD_ACTION. Check the buffer
+		 * length. It should at least have the size of one byte.
+		 */
+		if (*pLen < 1) {
+
+			*pLen = 1;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * The first byte contains the VPD action type we should
+		 * perform.
+		 */
+		switch (*pBuf) {
+
+		case SK_PNMI_VPD_IGNORE:
+			/* Nothing to do */
+			break;
+
+		case SK_PNMI_VPD_CREATE:
+			/*
+			 * We have to create a new VPD entry or we modify
+			 * an existing one. Check first the buffer length.
+			 */
+			if (*pLen < 4) {
+
+				*pLen = 4;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/*
+			 * Is the entry writable or does it belong to the
+			 * read-only area?
+			 */
+			if (!VpdMayWrite(KeyStr)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			Offset = (int)pBuf[3] & 0xFF;
+
+			SK_MEMCPY(Buf, pBuf + 4, Offset);
+			Buf[Offset] = 0;
+
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Write the new entry or modify an existing one */
+			Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
+			if (Ret == SK_PNMI_VPD_NOWRITE ) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			else if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
+					SK_PNMI_ERR025MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
+					SK_PNMI_ERR026MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case SK_PNMI_VPD_DELETE:
+			/* Check if the buffer size is plausible */
+			if (*pLen < 3) {
+
+				*pLen = 3;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			if (*pLen > 3) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/* Find the passed key in the array */
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+					break;
+				}
+			}
+			/*
+			 * If we cannot find the key it is wrong, so we
+			 * return an appropriate error value.
+			 */
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Ok, you wanted it and you will get it */
+			Ret = VpdDelete(pAC, IoC, KeyStr);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
+					SK_PNMI_ERR027MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
+					SK_PNMI_ERR028MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * General - OID handler function of various single instance OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int General(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int		Ret;
+	unsigned int	Index;
+	unsigned int	Len;
+	unsigned int	Offset;
+	unsigned int	Val;
+	SK_U8		Val8;
+	SK_U16		Val16;
+	SK_U32		Val32;
+	SK_U64		Val64;
+	SK_U64		Val64RxHwErrs = 0;
+	SK_U64		Val64TxHwErrs = 0;
+	SK_BOOL		Is64BitReq = SK_FALSE;
+	char		Buf[256];
+	int			MacType;
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action. We only allow get requests.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	MacType = pAC->GIni.GIMacType;
+
+	/*
+	 * Check length for the various supported OIDs
+	 */
+	switch (Id) {
+
+	case OID_GEN_XMIT_ERROR:
+	case OID_GEN_RCV_ERROR:
+	case OID_GEN_RCV_NO_BUFFER:
+#ifndef SK_NDIS_64BIT_CTR
+		if (*pLen < sizeof(SK_U32)) {
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+#else /* SK_NDIS_64BIT_CTR */
+
+		/*
+		 * for compatibility, at least 32bit are required for oid
+		 */
+		if (*pLen < sizeof(SK_U32)) {
+			/*
+			* but indicate handling for 64bit values,
+			* if insufficient space is provided
+			*/
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+		break;
+
+	case OID_SKGE_PORT_NUMBER:
+	case OID_SKGE_DEVICE_TYPE:
+	case OID_SKGE_RESULT:
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+	case OID_SKGE_TRAP_NUMBER:
+	case OID_SKGE_MDB_VERSION:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_CHIPSET:
+		if (*pLen < sizeof(SK_U16)) {
+
+			*pLen = sizeof(SK_U16);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+	case OID_SKGE_BUS_SPEED:
+	case OID_SKGE_BUS_WIDTH:
+	case OID_SKGE_SENSOR_NUMBER:
+	case OID_SKGE_CHKSM_NUMBER:
+		if (*pLen < sizeof(SK_U8)) {
+
+			*pLen = sizeof(SK_U8);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+	case OID_SKGE_TX_RETRY:
+	case OID_SKGE_RX_INTR_CTS:
+	case OID_SKGE_TX_INTR_CTS:
+	case OID_SKGE_RX_NO_BUF_CTS:
+	case OID_SKGE_TX_NO_BUF_CTS:
+	case OID_SKGE_TX_USED_DESCR_NO:
+	case OID_SKGE_RX_DELIVERED_CTS:
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+	case OID_SKGE_RX_HW_ERROR_CTS:
+	case OID_SKGE_TX_HW_ERROR_CTS:
+	case OID_SKGE_IN_ERRORS_CTS:
+	case OID_SKGE_OUT_ERROR_CTS:
+	case OID_SKGE_ERR_RECOVERY_CTS:
+	case OID_SKGE_SYSUPTIME:
+		if (*pLen < sizeof(SK_U64)) {
+
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		/* Checked later */
+		break;
+	}
+
+	/* Update statistic */
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		/* Force the XMAC to update its statistic counters and
+		 * Increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Some OIDs consist of multiple hardware counters. Those
+		 * values which are contained in all of them will be added
+		 * now.
+		 */
+		switch (Id) {
+
+		case OID_SKGE_RX_HW_ERROR_CTS:
+		case OID_SKGE_IN_ERRORS_CTS:
+		case OID_GEN_RCV_ERROR:
+			Val64RxHwErrs =
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
+		break;
+
+		case OID_SKGE_TX_HW_ERROR_CTS:
+		case OID_SKGE_OUT_ERROR_CTS:
+		case OID_GEN_XMIT_ERROR:
+			Val64TxHwErrs =
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
+			break;
+		}
+	}
+
+	/*
+	 * Retrieve value
+	 */
+	switch (Id) {
+
+	case OID_SKGE_SUPPORTED_LIST:
+		Len = ID_TABLE_SIZE * sizeof(SK_U32);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		for (Offset = 0, Index = 0; Offset < Len;
+			Offset += sizeof(SK_U32), Index ++) {
+
+			Val32 = (SK_U32)IdTable[Index].Id;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+		}
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_PORT_NUMBER:
+		Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DEVICE_TYPE:
+		Val32 = (SK_U32)pAC->Pnmi.DeviceType;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DRIVER_DESCR:
+		if (pAC->Pnmi.pDriverDescription == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
+				SK_PNMI_ERR007MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
+				SK_PNMI_ERR029MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_DRIVER_VERSION:
+		if (pAC->Pnmi.pDriverVersion == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+				SK_PNMI_ERR030MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+				SK_PNMI_ERR031MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_DESCR:
+		/*
+		 * The hardware description is located in the VPD. This
+		 * query may move to the initialisation routine. But
+		 * the VPD data is cached and therefore a call here
+		 * will not make much difference.
+		 */
+		Len = 256;
+		if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
+				SK_PNMI_ERR032MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		Len ++;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
+				SK_PNMI_ERR033MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, Buf, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_VERSION:
+		/* Oh, I love to do some string manipulation */
+		if (*pLen < 5) {
+
+			*pLen = 5;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
+		pBuf[0] = 4;
+		pBuf[1] = 'v';
+		pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
+		pBuf[3] = '.';
+		pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
+		*pLen = 5;
+		break;
+
+	case OID_SKGE_CHIPSET:
+		Val16 = pAC->Pnmi.Chipset;
+		SK_PNMI_STORE_U16(pBuf, Val16);
+		*pLen = sizeof(SK_U16);
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+		*pBuf = (char)SK_PNMI_BUS_PCI;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_SPEED:
+		*pBuf = pAC->Pnmi.PciBusSpeed;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_WIDTH:
+		*pBuf = pAC->Pnmi.PciBusWidth;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_RESULT:
+		Val32 = pAC->Pnmi.TestResult;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_SENSOR_NUMBER:
+		*pBuf = (char)pAC->I2c.MaxSens;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_CHKSM_NUMBER:
+		*pBuf = SKCS_NUM_PROTOCOLS;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_TRAP_NUMBER:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		Val32 = (SK_U32)Val;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TRAP:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		CopyTrapQueue(pAC, pBuf);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+/* XXX Not yet implemented by RLMT therefore we return zero elements */
+		Val32 = 0;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
+					pAC->Pnmi.BufPort[1].TxSwQueueLen;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxSwQueueLen +
+					pAC->Pnmi.Port[1].TxSwQueueLen;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
+					pAC->Pnmi.BufPort[1].TxSwQueueMax;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
+					pAC->Pnmi.Port[1].TxSwQueueMax;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_RETRY:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
+					pAC->Pnmi.BufPort[1].TxRetryCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxRetryCts +
+					pAC->Pnmi.Port[1].TxRetryCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_INTR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
+					pAC->Pnmi.BufPort[1].RxIntrCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxIntrCts +
+					pAC->Pnmi.Port[1].RxIntrCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_INTR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
+					pAC->Pnmi.BufPort[1].TxIntrCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxIntrCts +
+					pAC->Pnmi.Port[1].TxIntrCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_NO_BUF_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
+					pAC->Pnmi.Port[1].RxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_NO_BUF_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
+					pAC->Pnmi.Port[1].TxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_USED_DESCR_NO:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
+					pAC->Pnmi.BufPort[1].TxUsedDescrNo;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
+					pAC->Pnmi.Port[1].TxUsedDescrNo;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_DELIVERED_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxDeliveredCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
+					pAC->Pnmi.Port[1].RxDeliveredCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
+					pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_IN_ERRORS_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64RxHwErrs +
+					pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64RxHwErrs +
+					pAC->Pnmi.Port[0].RxNoBufCts +
+					pAC->Pnmi.Port[1].RxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_OUT_ERROR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64TxHwErrs +
+					pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64TxHwErrs +
+					pAC->Pnmi.Port[0].TxNoBufCts +
+					pAC->Pnmi.Port[1].TxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_ERR_RECOVERY_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
+					pAC->Pnmi.BufPort[1].ErrRecoveryCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
+					pAC->Pnmi.Port[1].ErrRecoveryCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_SYSUPTIME:
+		Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		Val64 -= pAC->Pnmi.StartUpTime;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_MDB_VERSION:
+		Val32 = SK_PNMI_MDB_VERSION;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_RCV_ERROR:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_XMIT_ERROR:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+		}
+		else {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_RCV_NO_BUFFER:
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+		Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
+			SK_PNMI_ERR034MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
+ *
+ * Description:
+ *	Get/Presets/Sets the RLMT OIDs.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Rlmt(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	int		Ret;
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_EVPARA	EventParam;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Check instance. Only single instance OIDs are allowed here.
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Perform the requested action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check if the buffer length is large enough.
+		 */
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			if (*pLen < sizeof(SK_U8)) {
+
+				*pLen = sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+		case OID_SKGE_RLMT_CHANGE_TIME:
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
+				SK_PNMI_ERR035MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update RLMT statistic and increment semaphores to indicate
+		 * that an update was already done. Maybe RLMT will hold its
+		 * statistic always up to date some time. Then we can
+		 * remove this type of call.
+		 */
+		if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.RlmtUpdatedFlag ++;
+
+		/*
+		 * Retrieve Value
+		*/
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			*pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+			*pBuf = 0;
+			/*
+			 * If multiple ports may become active this OID
+			 * doesn't make sense any more. A new variable in
+			 * the port structure should be created. However,
+			 * for this variable the first active port is
+			 * returned.
+			 */
+			PhysPortMax = pAC->GIni.GIMacsFound;
+
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
+					break;
+				}
+			}
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+			Val64 = pAC->Pnmi.RlmtChangeCts;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_TIME:
+			Val64 = pAC->Pnmi.RlmtChangeTime;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+			Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			Val64 = pAC->Pnmi.RlmtChangeThreshold;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("Rlmt: Unknown OID should be handled before"));
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		pAC->Pnmi.RlmtUpdatedFlag --;
+	}
+	else {
+		/* Perform a preset or set */
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) ||
+				(*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
+				*(SK_U8 *)pBuf > 15) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/* Send an event to RLMT to change the mode */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] |= (SK_U32)(*pBuf);
+			EventParam.Para32[1] = 0;
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
+					SK_PNMI_ERR037MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
+				(SK_U8)pAC->GIni.GIMacsFound) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/*
+			 * Send an event to RLMT change the preferred port.
+			 * A param of -1 means automatic mode. RLMT will
+			 * make the decision which is the preferred port.
+			 */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+			EventParam.Para32[1] = NetIndex;
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
+					SK_PNMI_ERR038MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/*
+			 * There are not many restrictions to the
+			 * value range.
+			 */
+			if (*pLen != sizeof(SK_U64)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/*
+			 * Store the new threshold, which will be taken
+			 * on the next timer event.
+			 */
+			SK_PNMI_READ_U64(pBuf, Val64);
+			pAC->Pnmi.RlmtChangeThreshold = Val64;
+			break;
+
+		default:
+			/* The other OIDs are not be able for set */
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
+ *
+ * Description:
+ *	Performs get requests on multiple instance variables.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int RlmtStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int		Ret;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+	/*
+	 * Calculate the port indexes from the instance
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+
+	if ((Instance != (SK_U32)(-1))) {
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > PhysPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		/* Single net mode */
+		PhysPortIndex = Instance - 1;
+
+		/* Dual net mode */
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+		}
+
+		/* Both net modes */
+		Limit = PhysPortIndex + 1;
+	}
+	else {
+		/* Single net mode */
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+
+		/* Dual net mode */
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+			Limit = PhysPortIndex + 1;
+		}
+	}
+
+	/*
+	 * Currently only get requests are allowed.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check if the buffer length is large enough.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_RLMT_PORT_INDEX:
+	case OID_SKGE_RLMT_STATUS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_RLMT_TX_HELLO_CTS:
+	case OID_SKGE_RLMT_RX_HELLO_CTS:
+	case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+	case OID_SKGE_RLMT_RX_SP_CTS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
+			SK_PNMI_ERR039MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Update statistic and increment semaphores to indicate that
+	 * an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+
+	/*
+	 * Get value
+	 */
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_PORT_INDEX:
+			Val32 = PhysPortIndex;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_STATUS:
+			if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_INIT ||
+				pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_DOWN) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ERROR;
+			}
+			else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
+			}
+			else {
+				Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
+			}
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_TX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_SP_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("RlmtStat: Unknown OID should be errored before"));
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateConf - OID handler function of OIDs concerning the configuration
+ *
+ * Description:
+ *	Get/Presets/Sets the OIDs concerning the configuration.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int MacPrivateConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	char		Val8;
+	int		Ret;
+	SK_EVPARA	EventParam;
+	SK_U32		Val32;
+
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		 */
+		switch (Id) {
+
+		case OID_SKGE_PMD:
+		case OID_SKGE_CONNECTOR:
+		case OID_SKGE_LINK_CAP:
+		case OID_SKGE_LINK_MODE:
+		case OID_SKGE_LINK_MODE_STATUS:
+		case OID_SKGE_LINK_STATUS:
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+		case OID_SKGE_FLOWCTRL_STATUS:
+		case OID_SKGE_PHY_OPERATION_CAP:
+		case OID_SKGE_PHY_OPERATION_MODE:
+		case OID_SKGE_PHY_OPERATION_STATUS:
+		case OID_SKGE_SPEED_CAP:
+		case OID_SKGE_SPEED_MODE:
+		case OID_SKGE_SPEED_STATUS:
+			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
+
+				*pLen = (Limit - LogPortIndex) *
+					sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+	case OID_SKGE_MTU:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
+				SK_PNMI_ERR041MSG);
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update statistic and increment semaphore to indicate
+		 * that an update was already done.
+		 */
+		if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.SirqUpdatedFlag ++;
+
+		/*
+		 * Get value
+		 */
+		Offset = 0;
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_PMD:
+				*(pBuf + Offset) = pAC->Pnmi.PMD;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_CONNECTOR:
+				*(pBuf + Offset) = pAC->Pnmi.Connector;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkCap;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkCap;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_LINK_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkModeConf;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkModeConf;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_LINK_MODE_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) =
+							CalculateLinkModeStatus(pAC,
+								IoC, PhysPortIndex);
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+					*(pBuf + Offset) = CalculateLinkModeStatus(pAC, IoC, NetIndex);
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_LINK_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) =
+							CalculateLinkStatus(pAC,
+								IoC, PhysPortIndex);
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = CalculateLinkStatus(pAC, IoC, NetIndex);
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_FLOWCTRL_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlCap;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_FLOWCTRL_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlMode;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_FLOWCTRL_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlStatus;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_PHY_OPERATION_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSCap;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSCap;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_PHY_OPERATION_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSMode;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSMode;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_PHY_OPERATION_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSStatus;
+					}
+					Offset += sizeof(char);
+				}
+				else {
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSStatus;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_SPEED_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeedCap;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_SPEED_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeed;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeed;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_SPEED_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeedUsed;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_MTU:
+				Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
+				SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+				Offset += sizeof(SK_U32);
+				break;
+
+			default:
+				SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+					("MacPrivateConf: Unknown OID should be handled before"));
+
+				pAC->Pnmi.SirqUpdatedFlag --;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_LINK_MODE:
+	case OID_SKGE_FLOWCTRL_MODE:
+	case OID_SKGE_PHY_OPERATION_MODE:
+	case OID_SKGE_SPEED_MODE:
+		if (*pLen < Limit - LogPortIndex) {
+
+			*pLen = Limit - LogPortIndex;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != Limit - LogPortIndex) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+	case OID_SKGE_MTU:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != sizeof(SK_U32)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+    default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Perform preset or set
+	 */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_LMODE_HALF ||
+				(LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
+				(LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new link mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_LMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR043,
+							SK_PNMI_ERR043MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new link mode to
+				 * the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR043,
+						SK_PNMI_ERR043MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_FLOW_MODE_NONE ||
+				(LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
+				(LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_FLOWMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR044,
+							SK_PNMI_ERR044MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_FLOWMODE, EventParam)
+					> 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR044,
+						SK_PNMI_ERR044MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE :
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+				/* mode of this port remains unchanged */
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_MS_MODE_AUTO ||
+				(LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
+				(LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with new master/slave (role) mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_ROLE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR042,
+							SK_PNMI_ERR042MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new master/slave
+				 * (role) mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_ROLE, EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR042,
+						SK_PNMI_ERR042MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < (SK_LSPEED_AUTO) ||
+				(LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
+				(LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_SPEED,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR045,
+							SK_PNMI_ERR045MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_SPEED,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR045,
+						SK_PNMI_ERR045MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_MTU :
+			/* Check the value range */
+			Val32 = *(SK_U32*)(pBuf + Offset);
+			if (Val32 == 0) {
+				/* mtu of this port remains unchanged */
+				Offset += sizeof(SK_U32);
+				break;
+			}
+			if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			Offset += sizeof(SK_U32);
+			break;
+
+		default:
+	    SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+		("MacPrivateConf: Unknown OID should be handled before set"));
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Monitor - OID handler function for RLMT_MONITOR_XXX
+ *
+ * Description:
+ *	Because RLMT currently does not support the monitoring of
+ *	remote adapter cards, we return always an empty table.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Monitor(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Entries;
+
+
+	/*
+	 * Calculate instance if wished.
+	 */
+/* XXX Not yet implemented. Return always an empty table. */
+	Entries = 0;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > Entries)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance - 1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = Entries;
+	}
+
+	/*
+	 * Get/Set value
+	*/
+	if (Action == SK_PNMI_GET) {
+
+		for (Offset=0; Index < Limit; Index ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_RLMT_MONITOR_INDEX:
+			case OID_SKGE_RLMT_MONITOR_ADDR:
+			case OID_SKGE_RLMT_MONITOR_ERRS:
+			case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
+			case OID_SKGE_RLMT_MONITOR_ADMIN:
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
+					SK_PNMI_ERR046MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+	else {
+		/* Only MONITOR_ADMIN can be set */
+		if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/* Check if the length is plausible */
+		if (*pLen < (Limit - Index)) {
+
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		/* Okay, we have a wide value range */
+		if (*pLen != (Limit - Index)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+/*
+		for (Offset=0; Index < Limit; Index ++) {
+		}
+*/
+/*
+ * XXX Not yet implemented. Return always BAD_VALUE, because the table
+ * is empty.
+ */
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * VirtualConf - Calculates the values of configuration OIDs for virtual port
+ *
+ * Description:
+ *	We handle here the get of the configuration group OIDs, which are
+ *	a little bit complicated. The virtual port consists of all currently
+ *	active physical ports. If multiple ports are active and configured
+ *	differently we get in some trouble to return a single value. So we
+ *	get the value of the first active port and compare it with that of
+ *	the other active ports. If they are not the same, we return a value
+ *	that indicates that the state is indeterminated.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void VirtualConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf)		/* Buffer to which to mgmt data will be retrieved */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	SK_U8		Val8;
+	SK_BOOL		PortActiveFlag;
+
+
+	*pBuf = 0;
+	PortActiveFlag = SK_FALSE;
+	PhysPortMax = pAC->GIni.GIMacsFound;
+
+	for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+		PhysPortIndex ++) {
+
+		/* Check if the physical port is active */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			continue;
+		}
+
+		PortActiveFlag = SK_TRUE;
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_CAP:
+
+			/*
+			 * Different capabilities should not happen, but
+			 * in the case of the cases OR them all together.
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PLinkCap;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode than the first one we return a value that
+			 * indicates that the link mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkModeConf
+				) {
+
+				*pBuf = SK_LMODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			/* Get the link mode of the physical port */
+			Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode status than the first one we return a value
+			 * that indicates that the link mode status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			/* Get the link status of the physical port */
+			Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * status than the first one, we return a value
+			 * that indicates that the link status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode) {
+
+				*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus) {
+
+				*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_PHY_OPERATION_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PMSCap;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PMSMode) {
+
+				*pBuf = SK_MS_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PMSStatus) {
+
+				*pBuf = SK_MS_STAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkSpeed) {
+
+				*pBuf = SK_LSPEED_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_SPEED_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed) {
+
+				*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			}
+			break;
+		}
+	}
+
+	/*
+	 * If no port is active return an indeterminated answer
+	 */
+	if (!PortActiveFlag) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_CAP:
+			*pBuf = SK_LMODE_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			*pBuf = SK_LMODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+			*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_CAP:
+			*pBuf = SK_MS_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			*pBuf = SK_MS_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			*pBuf = SK_MS_STAT_INDETERMINATED;
+			break;
+		case OID_SKGE_SPEED_CAP:
+			*pBuf = SK_LSPEED_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			*pBuf = SK_LSPEED_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_STATUS:
+			*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			break;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkStatus - Determins the link status of a physical port
+ *
+ * Description:
+ *	Determins the link status the following way:
+ *	  LSTAT_PHY_DOWN:  Link is down
+ *	  LSTAT_AUTONEG:   Auto-negotiation failed
+ *	  LSTAT_LOG_DOWN:  Link is up but RLMT did not yet put the port
+ *	                   logically up.
+ *	  LSTAT_LOG_UP:    RLMT marked the port as up
+ *
+ * Returns:
+ *	Link status of physical port
+ */
+PNMI_STATIC SK_U8 CalculateLinkStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+
+	if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {
+
+		Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
+	}
+	else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {
+
+		Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
+				}
+	else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {
+
+		Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
+	}
+	else {
+		Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkModeStatus - Determins the link mode status of a phys. port
+ *
+ * Description:
+ *	The COMMON module only tells us if the mode is half or full duplex.
+ *	But in the decade of auto sensing it is usefull for the user to
+ *	know if the mode was negotiated or forced. Therefore we have a
+ *	look to the mode, which was last used by the negotiation process.
+ *
+ * Returns:
+ *	The link mode status
+ */
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+
+	/* Get the current mode, which can be full or half duplex */
+	Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;
+
+	/* Check if no valid mode could be found (link is down) */
+	if (Result < SK_LMODE_STAT_HALF) {
+
+		Result = SK_LMODE_STAT_UNKNOWN;
+	}
+	else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {
+
+		/*
+		 * Auto-negotiation was used to bring up the link. Change
+		 * the already found duplex status that it indicates
+		 * auto-negotiation was involved.
+		 */
+		if (Result == SK_LMODE_STAT_HALF) {
+
+			Result = SK_LMODE_STAT_AUTOHALF;
+		}
+		else if (Result == SK_LMODE_STAT_FULL) {
+
+			Result = SK_LMODE_STAT_AUTOFULL;
+		}
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * GetVpdKeyArr - Obtain an array of VPD keys
+ *
+ * Description:
+ *	Read the VPD keys and build an array of VPD keys, which are
+ *	easy to access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int GetVpdKeyArr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+char *pKeyArr,		/* Ptr KeyArray */
+unsigned int KeyArrLen,	/* Length of array in bytes */
+unsigned int *pKeyNo)	/* Number of keys */
+{
+	unsigned int		BufKeysLen = SK_PNMI_VPD_BUFSIZE;
+	char			BufKeys[SK_PNMI_VPD_BUFSIZE];
+	unsigned int		StartOffset;
+	unsigned int		Offset;
+	int			Index;
+	int			Ret;
+
+
+	SK_MEMSET(pKeyArr, 0, KeyArrLen);
+
+	/*
+	 * Get VPD key list
+	 */
+	Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
+		(int *)pKeyNo);
+	if (Ret > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
+			SK_PNMI_ERR014MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	/* If no keys are available return now */
+	if (*pKeyNo == 0 || BufKeysLen == 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+	/*
+	 * If the key list is too long for us trunc it and give a
+	 * errorlog notification. This case should not happen because
+	 * the maximum number of keys is limited due to RAM limitations
+	 */
+	if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
+			SK_PNMI_ERR015MSG);
+
+		*pKeyNo = SK_PNMI_VPD_ENTRIES;
+	}
+
+	/*
+	 * Now build an array of fixed string length size and copy
+	 * the keys together.
+	 */
+	for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
+		Offset ++) {
+
+		if (BufKeys[Offset] != 0) {
+
+			continue;
+		}
+
+		if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
+				SK_PNMI_ERR016MSG);
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+
+		Index ++;
+		StartOffset = Offset + 1;
+	}
+
+	/* Last key not zero terminated? Get it anyway */
+	if (StartOffset < Offset) {
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SirqUpdate - Let the SIRQ update its internal values
+ *
+ * Description:
+ *	Just to be sure that the SIRQ module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int SirqUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC)	/* IO context handle */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.SirqUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
+			SK_PNMI_ERR047MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtUpdate - Let the RLMT update its internal values
+ *
+ * Description:
+ *	Just to be sure that the RLMT module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int RlmtUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC,	/* IO context handle */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.RlmtUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
+			SK_PNMI_ERR048MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacUpdate - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values we send a command so that the statistic data will
+ *	be written to apredefined memory area on the adapter.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int MacUpdate(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+unsigned int FirstMac,	/* Index of the first Mac to be updated */
+unsigned int LastMac)	/* Index of the last Mac to be updated */
+{
+	unsigned int	MacIndex;
+
+	/*
+	 * Were the statistics already updated during the
+	 * current PNMI call?
+	 */
+	if (pAC->Pnmi.MacUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an update command to all MACs specified */
+	for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
+
+		/*
+		 * 2002-09-13 pweber:	Freeze the current sw counters.
+		 *                      (That should be done as close as
+		 *                      possible to the update of the
+		 *                      hw counters)
+		 */
+		if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+			pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
+		}
+
+		/* 2002-09-13 pweber:  Update the hw counter  */
+		if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * GetStatVal - Retrieve an XMAC statistic counter
+ *
+ * Description:
+ *	Retrieves the statistic counter of a virtual or physical port. The
+ *	virtual port is identified by the index 0. It consists of all
+ *	currently active ports. To obtain the counter value for this port
+ *	we must add the statistic counter of all active ports. To grant
+ *	continuous counter values for the virtual port even when port
+ *	switches occur we must additionally add a delta value, which was
+ *	calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
+ *
+ * Returns:
+ *	Requested statistic value
+ */
+PNMI_STATIC SK_U64 GetStatVal(
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
+unsigned int LogPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex,		/* Index to statistic value */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_U64			Val = 0;
+
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {	/* Dual net mode */
+
+		PhysPortIndex = NetIndex;
+		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+	}
+	else {	/* Single Net mode */
+
+		if (LogPortIndex == 0) {
+
+			PhysPortMax = pAC->GIni.GIMacsFound;
+
+			/* Add counter of all active ports */
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					Val += GetPhysStatVal(pAC, IoC, PhysPortIndex,
+						StatIndex);
+				}
+			}
+
+			/* Correct value because of port switches */
+			Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+		}
+		else {
+			/* Get counter value of physical port */
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+		}
+	}
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * GetPhysStatVal - Get counter value for physical port
+ *
+ * Description:
+ *	Builds a 64bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	in software by monitoring counter overflow interrupts in the
+ *	event handler. To grant continous counter values during XMAC
+ *	resets (caused by a workaround) we must add a delta value.
+ *	The delta was calculated in the event handler when a
+ *	SK_PNMI_EVT_XMAC_RESET was received.
+ *
+ * Returns:
+ *	Counter value
+ */
+PNMI_STATIC SK_U64 GetPhysStatVal(
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
+unsigned int PhysPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex)		/* Index to statistic value */
+{
+	SK_U64	Val = 0;
+	SK_U32	LowVal = 0;
+	SK_U32	HighVal = 0;
+	SK_U16	Word;
+	int		MacType;
+
+	SK_PNMI_PORT	*pPnmiPrt;
+	SK_GEMACFUNC	*pFnMac;
+
+	MacType = pAC->GIni.GIMacType;
+
+	/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+	if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+		pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
+	}
+	else {
+		pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
+	}
+
+	pFnMac   = &pAC->GIni.GIFunc;
+
+	switch (StatIndex) {
+	case SK_PNMI_HTX:
+	case SK_PNMI_HRX:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_OCTET:
+	case SK_PNMI_HRX_OCTET:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+									  &LowVal);
+		break;
+
+	case SK_PNMI_HTX_BURST:
+	case SK_PNMI_HTX_EXCESS_DEF:
+	case SK_PNMI_HTX_CARRIER:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_MACC:
+		/* GMAC only supports PAUSE MAC control frames */
+		if (MacType == SK_MAC_GMAC) {
+			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, SK_PNMI_HTX_PMACC);
+
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_COL:
+	case SK_PNMI_HRX_UNDERSIZE:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+
+	case SK_PNMI_HTX_DEFFERAL:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+
+		/*
+		 * XMAC counts frames with deferred transmission
+		 * even in full-duplex mode.
+		 *
+		 * In full-duplex mode the counter remains constant!
+		 */
+		if ((pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
+			(pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_FULL)) {
+
+			LowVal = 0;
+			HighVal = 0;
+		}
+		else {
+			/* Otherwise get contents of hardware register. */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[SK_PNMI_HTX_DEFFERAL][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		break;
+
+	case SK_PNMI_HRX_BADOCTET:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+				      &LowVal);
+		break;
+
+	case SK_PNMI_HTX_OCTETLOW:
+	case SK_PNMI_HRX_OCTETLOW:
+	case SK_PNMI_HRX_BADOCTETLOW:
+		return (Val);
+
+	case SK_PNMI_HRX_LONGFRAMES:
+		/* For XMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_XMAC) {
+			return (pPnmiPrt->StatRxLongFrameCts);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HRX_TOO_LONG:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+						StatAddr[StatIndex][MacType].Reg,
+								&LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+		Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+		switch (MacType) {
+		case SK_MAC_GMAC:
+			/* For GMAC the SW counter is additionally managed by PNMI */
+			Val += pPnmiPrt->StatRxFrameTooLongCts;
+			break;
+
+		case SK_MAC_XMAC:
+			/*
+			 * Frames longer than IEEE 802.3 frame max size are counted
+			 * by XMAC in frame_too_long counter even reception of long
+			 * frames was enabled and the frame was correct.
+			 * So correct the value by subtracting RxLongFrame counter.
+			 */
+			Val -= pPnmiPrt->StatRxLongFrameCts;
+			break;
+
+		default:
+			break;
+		}
+
+		LowVal = (SK_U32)Val;
+		HighVal = (SK_U32)(Val >> 32);
+		break;
+
+	case SK_PNMI_HRX_SHORTS:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			/* GM_RXE_FRAG?? */
+			return (Val);
+		}
+
+		/*
+		 * XMAC counts short frame errors even if link down (#10620)
+		 *
+		 * If link-down the counter remains constant
+		 */
+		if (pAC->GIni.GP[PhysPortIndex].PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {
+
+			/* Otherwise get incremental difference */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+			Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+			Val -= pPnmiPrt->RxShortZeroMark;
+
+			LowVal = (SK_U32)Val;
+			HighVal = (SK_U32)(Val >> 32);
+		}
+		break;
+
+	case SK_PNMI_HRX_MACC:
+	case SK_PNMI_HRX_MACC_UNKWN:
+	case SK_PNMI_HRX_BURST:
+	case SK_PNMI_HRX_MISSED:
+	case SK_PNMI_HRX_FRAMING:
+	case SK_PNMI_HRX_CARRIER:
+	case SK_PNMI_HRX_IRLENGTH:
+	case SK_PNMI_HRX_SYMBOL:
+	case SK_PNMI_HRX_CEXT:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			/* GM_RXE_FRAG?? */
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HRX_PMACC_ERR:
+		/* For GMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_GMAC) {
+			return (pPnmiPrt->StatRxPMaccErr);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC_OCTET:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
+		break;
+
+	case SK_PNMI_HRX_FCS:
+		/*
+		 * Broadcom filters fcs errors and counts it in
+		 * Receive Error Counter register
+		 */
+		if (pAC->GIni.GP[PhysPortIndex].PhyType == SK_PHY_BCOM) {
+			/* do not read while not initialized (PHY_READ hangs!)*/
+			if (pAC->GIni.GP[PhysPortIndex].PState) {
+				PHY_READ(IoC, &pAC->GIni.GP[PhysPortIndex],
+						 PhysPortIndex, PHY_BCOM_RE_CTR,
+						 &Word);
+
+				LowVal = Word;
+			}
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		else {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		break;
+
+	default:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+	}
+
+	Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+	/* Correct value because of possible XMAC reset. XMAC Errata #2 */
+	Val += pPnmiPrt->CounterOffset[StatIndex];
+
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * ResetCounter - Set all counters and timestamps to zero
+ *
+ * Description:
+ *	Notifies other common modules which store statistic data to
+ *	reset their counters and finally reset our own counters.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void ResetCounter(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 NetIndex)
+{
+	unsigned int	PhysPortIndex;
+	SK_EVPARA	EventParam;
+
+
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+
+	/* Notify sensor module */
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
+
+	/* Notify RLMT module */
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+	EventParam.Para32[1] = 0;
+
+	/* Notify SIRQ module */
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
+
+	/* Notify CSUM module */
+#ifdef SK_USE_CSUM
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
+		EventParam);
+#endif
+
+	/* Clear XMAC statistic */
+	for (PhysPortIndex = 0; PhysPortIndex <
+		(unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
+
+		(void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);
+
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			CounterOffset, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].CounterOffset));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatSyncOctetsCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxLongFrameCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxFrameTooLongCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxPMaccErr));
+	}
+
+	/*
+	 * Clear local statistics
+	 */
+	SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0,
+		  sizeof(pAC->Pnmi.VirtualCounterOffset));
+	pAC->Pnmi.RlmtChangeCts = 0;
+	pAC->Pnmi.RlmtChangeTime = 0;
+	SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
+		sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
+	pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
+	pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
+	pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
+	pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
+	pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
+}
+
+/*****************************************************************************
+ *
+ * GetTrapEntry - Get an entry in the trap buffer
+ *
+ * Description:
+ *	The trap buffer stores various events. A user application somehow
+ *	gets notified that an event occured and retrieves the trap buffer
+ *	contens (or simply polls the buffer). The buffer is organized as
+ *	a ring which stores the newest traps at the beginning. The oldest
+ *	traps are overwritten by the newest ones. Each trap entry has a
+ *	unique number, so that applications may detect new trap entries.
+ *
+ * Returns:
+ *	A pointer to the trap entry
+ */
+PNMI_STATIC char* GetTrapEntry(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* SNMP ID of the trap */
+unsigned int Size)	/* Space needed for trap entry */
+{
+	unsigned int		BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int		BufFree = pAC->Pnmi.TrapBufFree;
+	unsigned int		Beg = pAC->Pnmi.TrapQueueBeg;
+	unsigned int		End = pAC->Pnmi.TrapQueueEnd;
+	char			*pBuf = &pAC->Pnmi.TrapBuf[0];
+	int			Wrap;
+	unsigned int		NeededSpace;
+	unsigned int		EntrySize;
+	SK_U32			Val32;
+	SK_U64			Val64;
+
+
+	/* Last byte of entry will get a copy of the entry length */
+	Size ++;
+
+	/*
+	 * Calculate needed buffer space */
+	if (Beg >= Size) {
+
+		NeededSpace = Size;
+		Wrap = SK_FALSE;
+	}
+	else {
+		NeededSpace = Beg + Size;
+		Wrap = SK_TRUE;
+	}
+
+	/*
+	 * Check if enough buffer space is provided. Otherwise
+	 * free some entries. Leave one byte space between begin
+	 * and end of buffer to make it possible to detect whether
+	 * the buffer is full or empty
+	 */
+	while (BufFree < NeededSpace + 1) {
+
+		if (End == 0) {
+
+			End = SK_PNMI_TRAP_QUEUE_LEN;
+		}
+
+		EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
+		BufFree += EntrySize;
+		End -= EntrySize;
+#ifdef DEBUG
+		SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
+#endif
+		if (End == BufPad) {
+#ifdef DEBUG
+			SK_MEMSET(pBuf, (char)(-1), End);
+#endif
+			BufFree += End;
+			End = 0;
+			BufPad = 0;
+		}
+	}
+
+	/*
+	 * Insert new entry as first entry. Newest entries are
+	 * stored at the beginning of the queue.
+	 */
+	if (Wrap) {
+
+		BufPad = Beg;
+		Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
+	}
+	else {
+		Beg = Beg - Size;
+	}
+	BufFree -= NeededSpace;
+
+	/* Save the current offsets */
+	pAC->Pnmi.TrapQueueBeg = Beg;
+	pAC->Pnmi.TrapQueueEnd = End;
+	pAC->Pnmi.TrapBufPad = BufPad;
+	pAC->Pnmi.TrapBufFree = BufFree;
+
+	/* Initialize the trap entry */
+	*(pBuf + Beg + Size - 1) = (char)Size;
+	*(pBuf + Beg) = (char)Size;
+	Val32 = (pAC->Pnmi.TrapUnique) ++;
+	SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
+	SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
+	Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+	SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);
+
+	return (pBuf + Beg);
+}
+
+/*****************************************************************************
+ *
+ * CopyTrapQueue - Copies the trap buffer for the TRAP OID
+ *
+ * Description:
+ *	On a query of the TRAP OID the trap buffer contents will be
+ *	copied continuously to the request buffer, which must be large
+ *	enough. No length check is performed.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void CopyTrapQueue(
+SK_AC *pAC,		/* Pointer to adapter context */
+char *pDstBuf)		/* Buffer to which the queued traps will be copied */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	DstOff = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+
+		/*
+		 * Last byte containing a copy of the length will
+		 * not be copied.
+		 */
+		*(pDstBuf + DstOff) = (char)(Len - 1);
+		SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
+		DstOff += Len - 1;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * GetTrapQueueLen - Get the length of the trap buffer
+ *
+ * Description:
+ *	Evaluates the number of currently stored traps and the needed
+ *	buffer size to retrieve them.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void GetTrapQueueLen(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int *pLen,	/* Length in Bytes of all queued traps */
+unsigned int *pEntries)	/* Returns number of trapes stored in queue */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	Entries = 0;
+	unsigned int	TotalLen = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+		TotalLen += Len - 1;
+		Entries ++;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+
+	*pEntries = Entries;
+	*pLen = TotalLen;
+}
+
+/*****************************************************************************
+ *
+ * QueueSimpleTrap - Store a simple trap to the trap buffer
+ *
+ * Description:
+ *	A simple trap is a trap with now additional data. It consists
+ *	simply of a trap code.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueSimpleTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId)		/* Type of sensor trap */
+{
+	GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
+}
+
+/*****************************************************************************
+ *
+ * QueueSensorTrap - Stores a sensor trap in the trap buffer
+ *
+ * Description:
+ *	Gets an entry in the trap buffer and fills it with sensor related
+ *	data.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueSensorTrap(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_U32 TrapId,			/* Type of sensor trap */
+unsigned int SensorIndex)	/* Index of sensor which caused the trap */
+{
+	char		*pBuf;
+	unsigned int	Offset;
+	unsigned int	DescrLen;
+	SK_U32		Val32;
+
+
+	/* Get trap buffer entry */
+	DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
+	pBuf = GetTrapEntry(pAC, TrapId,
+		SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
+	Offset = SK_PNMI_TRAP_SIMPLE_LEN;
+
+	/* Store additionally sensor trap related data */
+	Val32 = OID_SKGE_SENSOR_INDEX;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)SensorIndex;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+	Offset += 9;
+
+	Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = (char)DescrLen;
+	SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
+		DescrLen);
+	Offset += DescrLen + 5;
+
+	Val32 = OID_SKGE_SENSOR_TYPE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 1;
+	*(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
+	Offset += 6;
+
+	Val32 = OID_SKGE_SENSOR_VALUE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueRlmtNewMacTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int ActiveMac)	/* Index (0..n) of the currently active port */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
+		SK_PNMI_TRAP_RLMT_CHANGE_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueRlmtPortTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* Type of RLMT port trap */
+unsigned int PortIndex)	/* Index of the port, which changed its state */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_INDEX;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
+}
+
+/*****************************************************************************
+ *
+ * CopyMac - Copies a MAC address
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void CopyMac(
+char *pDst,		/* Pointer to destination buffer */
+SK_MAC_ADDR *pMac)	/* Pointer of Source */
+{
+	int	i;
+
+
+	for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {
+
+		*(pDst + i) = pMac->a[i];
+	}
+}
+
+
+#ifdef SK_POWER_MGMT
+/*****************************************************************************
+ *
+ * PowerManagement - OID handler function of PowerManagement OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+PNMI_STATIC int PowerManagement(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+
+	SK_U32	RetCode = SK_PNMI_ERR_GENERAL;
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		 */
+		switch (Id) {
+
+		case OID_PNP_CAPABILITIES:
+			if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {
+
+				*pLen = sizeof(SK_PNP_CAPABILITIES);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_PNP_QUERY_POWER:
+		case OID_PNP_ENABLE_WAKE_UP:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_PNP_SET_POWER:
+		case OID_PNP_ADD_WAKE_UP_PATTERN:
+		case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040,
+				SK_PNMI_ERR040MSG);
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Get value
+		 */
+		switch (Id) {
+
+		case OID_PNP_CAPABILITIES:
+			RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
+			break;
+
+		case OID_PNP_QUERY_POWER:
+			/* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
+			 the miniport to indicate whether it can transition its NIC
+			 to the low-power state.
+			 A miniport driver must always return NDIS_STATUS_SUCCESS
+			 to a query of OID_PNP_QUERY_POWER. */
+			RetCode = SK_PNMI_ERR_OK;
+			break;
+
+			/* NDIS handles these OIDs as write-only.
+			 * So in case of get action the buffer with written length = 0
+			 * is returned
+			 */
+		case OID_PNP_SET_POWER:
+		case OID_PNP_ADD_WAKE_UP_PATTERN:
+		case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+			*pLen = 0;
+			RetCode = SK_PNMI_ERR_OK;
+			break;
+
+		case OID_PNP_ENABLE_WAKE_UP:
+			RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
+			break;
+
+		default:
+			RetCode = SK_PNMI_ERR_GENERAL;
+			break;
+		}
+
+		return (RetCode);
+	}
+
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	switch (Id) {
+	case OID_PNP_SET_POWER:
+	case OID_PNP_ENABLE_WAKE_UP:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != sizeof(SK_U32)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+	case OID_PNP_ADD_WAKE_UP_PATTERN:
+	case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+    default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Perform preset or set
+	 */
+
+	/* POWER module does not support PRESET action */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK);
+	}
+
+	switch (Id) {
+	case OID_PNP_SET_POWER:
+		RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);
+		break;
+
+	case OID_PNP_ADD_WAKE_UP_PATTERN:
+		RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);
+		break;
+
+	case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen);
+		break;
+
+	case OID_PNP_ENABLE_WAKE_UP:
+		RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
+		break;
+
+	default:
+		RetCode = SK_PNMI_ERR_GENERAL;
+	}
+
+	return (RetCode);
+}
+#endif /* SK_POWER_MGMT */
+
+
+/*****************************************************************************
+ *
+ * Vct - OID handler function of  OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was performed successfully.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter).
+ *	SK_PNMI_ERR_READ_ONLY	 Only the Get action is allowed.
+ *
+ */
+
+PNMI_STATIC int Vct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which the mgmt data will be copied */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (-1,2..n) that is to be queried */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		LogPortMax;
+	SK_U32		PhysPortMax;
+	SK_U32		PhysPortIndex;
+	SK_U32		Limit;
+	SK_U32		Offset;
+	SK_BOOL		Link;
+	SK_U32		RetCode = SK_PNMI_ERR_GENERAL;
+	int		i;
+	SK_EVPARA	Para;
+	SK_U32		CableLength;
+
+	/*
+	 * Calculate the port indexes from the instance.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	/* Dual net mode? */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32) (-1))) {
+		/* Check instance range. */
+		if ((Instance < 2) || (Instance > LogPortMax)) {
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+		}
+		else {
+			PhysPortIndex = Instance - 2;
+		}
+		Limit = PhysPortIndex + 1;
+	}
+	else {	/*
+		 * Instance == (SK_U32) (-1), get all Instances of that OID.
+		 *
+		 * Not implemented yet. May be used in future releases.
+		 */
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+	}
+
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	if (pPrt->PHWLinkUp) {
+		Link = SK_TRUE;
+	}
+	else {
+		Link = SK_FALSE;
+	}
+
+	/*
+	 * Check MAC type.
+	 */
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/* Initialize backup data pointer. */
+	pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+
+	/*
+	 * Check action type.
+	 */
+	if (Action == SK_PNMI_GET) {
+		/*
+		 * Check length.
+		 */
+		switch (Id) {
+
+		case OID_SKGE_VCT_GET:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_VCT_STATUS:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Get value.
+		 */
+		Offset = 0;
+		for (; PhysPortIndex < Limit; PhysPortIndex++) {
+			switch (Id) {
+
+			case OID_SKGE_VCT_GET:
+				if ((Link == SK_FALSE) &&
+					(pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
+					RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+					if (RetCode == 0) {
+						pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+						pAC->Pnmi.VctStatus[PhysPortIndex] |=
+							(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+
+						/* Copy results for later use to PNMI struct. */
+						for (i = 0; i < 4; i++)  {
+							if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+								if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
+									pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+								}
+							}
+							if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
+								CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+							}
+							else {
+								CableLength = 0;
+							}
+							pVctBackupData->PMdiPairLen[i] = CableLength;
+							pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+						}
+
+						Para.Para32[0] = PhysPortIndex;
+						Para.Para32[1] = -1;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+						SkEventDispatcher(pAC, IoC);
+					}
+					else {
+						; /* VCT test is running. */
+					}
+				}
+
+				/* Get all results. */
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				*(pBuf + Offset) = pPrt->PCableLen;
+				Offset += sizeof(SK_U8);
+				for (i = 0; i < 4; i++)  {
+					SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
+					Offset += sizeof(SK_U32);
+				}
+				for (i = 0; i < 4; i++)  {
+					*(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
+					Offset += sizeof(SK_U8);
+				}
+
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+
+			case OID_SKGE_VCT_STATUS:
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+
+			default:
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		} /* for */
+		*pLen = Offset;
+		return (RetCode);
+
+	} /* if SK_PNMI_GET */
+
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+
+	/*
+	 * Check length.
+	 */
+	switch (Id) {
+	case OID_SKGE_VCT_SET:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/*
+	 * Perform preset or set.
+	 */
+
+	/* VCT does not support PRESET action. */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK);
+	}
+
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex++) {
+		switch (Id) {
+		case OID_SKGE_VCT_SET: /* Start VCT test. */
+			if (Link == SK_FALSE) {
+				SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
+
+				RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
+				if (RetCode == 0) { /* RetCode: 0 => Start! */
+					pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
+
+					/*
+					 * Start VCT timer counter.
+					 */
+					SK_MEMSET((char *) &Para, 0, sizeof(Para));
+					Para.Para32[0] = PhysPortIndex;
+					Para.Para32[1] = -1;
+					SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+						4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+				else { /* RetCode: 2 => Running! */
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+			}
+			else { /* RetCode: 4 => Link! */
+				RetCode = 4;
+				SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+				RetCode = SK_PNMI_ERR_OK;
+			}
+			Offset += sizeof(SK_U32);
+			break;
+
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	} /* for */
+	*pLen = Offset;
+	return (RetCode);
+
+} /* Vct */
+
+
+PNMI_STATIC void CheckVctStatus(
+SK_AC		*pAC,
+SK_IOC		IoC,
+char		*pBuf,
+SK_U32		Offset,
+SK_U32		PhysPortIndex)
+{
+	SK_GEPORT 	*pPrt;
+	SK_PNMI_VCT	*pVctData;
+	SK_U32		RetCode;
+	SK_U8		LinkSpeedUsed;
+
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+	pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
+	pVctData->VctStatus = SK_PNMI_VCT_NONE;
+
+	if (!pPrt->PHWLinkUp) {
+
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
+				pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+			}
+			else {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+
+		/* Check VCT test status. */
+		RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
+		if (RetCode == 2) { /* VCT test is running. */
+			pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
+		}
+		else { /* VCT data was copied to pAC here. Check PENDING state. */
+			if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+
+		if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
+		}
+	}
+	else {
+
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+		}
+
+		/* DSP only valid in 100/1000 modes. */
+		LinkSpeedUsed = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+		if (LinkSpeedUsed != SK_LSPEED_STAT_10MBPS) {
+			pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
+		}
+	}
+
+} /* CheckVctStatus */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c
new file mode 100644
index 0000000..e5a4f7e
--- /dev/null
+++ b/drivers/net/sk98lin/skgesirq.c
@@ -0,0 +1,2417 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.83 $
+ * Date:	$Date: 2003/02/05 15:10:59 $
+ * Purpose:	Special IRQ module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgesirq.c,v $
+ *	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
+ *	Removed testing of unused error bits in PHY ISR
+ *	Editorial changes.
+ *
+ *	Revision 1.80  2002/11/12 17:15:21  rschmidt
+ *	Replaced SkPnmiGetVar() by ...MacStatistic() in SkMacParity().
+ *	Editorial changes.
+ *
+ *	Revision 1.79  2002/10/14 15:14:51  rschmidt
+ *	Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
+ *	SkMacParity() depending on GIChipRev (HW-Bug #8).
+ *	Added error messages for GPHY Auto-Negotiation Error and
+ *	FIFO Overflow/Underrun in SkPhyIsrGmac().
+ *	Editorial changes.
+ *
+ *	Revision 1.78  2002/10/10 15:54:29  mkarl
+ *	changes for PLinkSpeedUsed
+ *
+ *	Revision 1.77  2002/09/12 08:58:51  rwahl
+ *	Retrieve counters needed for XMAC errata workarounds directly because
+ *	PNMI returns corrected counter values (e.g. #10620).
+ *
+ *	Revision 1.76  2002/08/16 15:21:54  rschmidt
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
+ *	Editorial changes.
+ *
+ *	Revision 1.75  2002/08/12 13:50:47  rschmidt
+ *	Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
+ *	SkMacParity() by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE (HW-Bug #8).
+ *	Added clearing of IS_IRQ_TIST_OV and IS_IRQ_SENSOR in SkGeHwErr().
+ *	Corrected handling of Link Up and Auto-Negotiation Over for GPHY.
+ *	in SkGePortCheckUpGmac().
+ *	Editorial changes.
+ *
+ *	Revision 1.74  2002/08/08 16:17:04  rschmidt
+ *	Added PhyType check for SK_HWEV_SET_ROLE event (copper only)
+ *	Changed Link Up check reading PHY Specific Status (YUKON)
+ *	Editorial changes
+ *
+ *	Revision 1.73  2002/07/15 18:36:53  rwahl
+ *	Editorial changes.
+ *
+ *	Revision 1.72  2002/07/15 15:46:26  rschmidt
+ *	Added new event: SK_HWEV_SET_SPEED
+ *	Editorial changes
+ *
+ *	Revision 1.71  2002/06/10 09:34:19  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.70  2002/06/05 08:29:18  rschmidt
+ *	SkXmRxTxEnable() replaced by SkMacRxTxEnable().
+ *	Editorial changes.
+ *
+ *	Revision 1.69  2002/04/25 13:03:49  rschmidt
+ *	Changes for handling YUKON.
+ *	Use of #ifdef OTHER_PHY to eliminate code for unused Phy types.
+ *	Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
+ *	SkMacIrqDisable().
+ *	Added handling for GMAC FIFO in SkMacParity().
+ *	Replaced all SkXm...() functions with SkMac...() to handle also
+ *	YUKON's GMAC.
+ *	Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced
+ *	by functions SkXmPhyRead(), SkXmPhyWrite().
+ *	Disabling all PHY interrupts moved to SkMacIrqDisable().
+ *	Added handling for GPHY IRQ in SkGeSirqIsr().
+ *	Removed status parameter from MAC IRQ handler SkMacIrq().
+ *	Added SkGePortCheckUpGmac(), SkPhyIsrGmac() for GMAC.
+ *	Editorial changes
+ *
+ *	Revision 1.68  2002/02/26 15:24:53  rwahl
+ *	Fix: no link with manual configuration (#10673). The previous fix for
+ *	#10639 was removed. So for RLMT mode = CLS the RLMT may switch to
+ *	misconfigured port. It should not occur for the other RLMT modes.
+ *
+ *	Revision 1.67  2001/11/20 09:19:58  rwahl
+ *	Reworked bugfix #10639 (no dependency to RLMT mode).
+ *
+ *	Revision 1.66  2001/10/26 07:52:53  afischer
+ *	Port switching bug in `check local link` mode
+ *
+ *	Revision 1.65  2001/02/23 13:41:51  gklug
+ *	fix: PHYS2INST should be used correctly for Dual Net operation
+ *	chg: do no longer work with older PNMI
+ *
+ *	Revision 1.64  2001/02/15 11:27:04  rassmann
+ *	Working with RLMT v1 if SK_MAX_NETS undefined.
+ *
+ *	Revision 1.63  2001/02/06 10:44:23  mkunz
+ *	- NetIndex added to interface functions of pnmi V4 with dual net support
+ *
+ *	Revision 1.62  2001/01/31 15:31:41  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *
+ *	Revision 1.61  2000/11/09 11:30:09  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *
+ *	Revision 1.60  2000/10/18 12:37:48  cgoos
+ *	Reinserted the comment for version 1.56.
+ *
+ *	Revision 1.59  2000/10/18 12:22:20  cgoos
+ *	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
+ *
+ *	Revision 1.57  2000/09/08 12:38:39  cgoos
+ *	Added forgotten variable declaration.
+ *
+ *	Revision 1.56  2000/09/08 08:12:13  cgoos
+ *	Changed handling of parity errors in SkGeHwErr (correct reset of error).
+ *
+ *	Revision 1.55  2000/06/19 08:36:25  cgoos
+ *	Changed comment.
+ *
+ *	Revision 1.54  2000/05/22 08:45:57  malthoff
+ *	Fix: #10523 is valid for all BCom PHYs.
+ *
+ *	Revision 1.53  2000/05/19 10:20:30  cgoos
+ *	Removed Solaris debug output code.
+ *
+ *	Revision 1.52  2000/05/19 10:19:37  cgoos
+ *	Added PHY state check in HWLinkDown.
+ *	Move PHY interrupt code to IS_EXT_REG case in SkGeSirqIsr.
+ *
+ *	Revision 1.51  2000/05/18 05:56:20  cgoos
+ *	Fixed typo.
+ *
+ *	Revision 1.50  2000/05/17 12:49:49  malthoff
+ *	Fixes BCom link bugs (#10523).
+ *
+ *	Revision 1.49  1999/12/17 11:02:50  gklug
+ *	fix: read PHY_STAT of Broadcom chip more often to assure good status
+ *
+ *	Revision 1.48  1999/12/06 10:01:17  cgoos
+ *	Added SET function for Role.
+ *
+ *	Revision 1.47  1999/11/22 13:34:24  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.46  1999/09/16 10:30:07  cgoos
+ *	Removed debugging output statement from Linux.
+ *
+ *	Revision 1.45  1999/09/16 07:32:55  cgoos
+ *	Fixed dual-port copperfield bug (PHY_READ from resetted port).
+ *	Removed some unused variables.
+ *
+ *	Revision 1.44  1999/08/03 15:25:04  cgoos
+ *	Removed workaround for disabled interrupts in half duplex mode.
+ *
+ *	Revision 1.43  1999/08/03 14:27:58  cgoos
+ *	Removed SENSE mode code from SkGePortCheckUpBcom.
+ *
+ *	Revision 1.42  1999/07/26 09:16:54  cgoos
+ *	Added some typecasts to avoid compiler warnings.
+ *
+ *	Revision 1.41  1999/05/19 07:28:59  cgoos
+ *	Changes for 1000Base-T.
+ *
+ *	Revision 1.40  1999/04/08 13:59:39  gklug
+ *	fix: problem with 3Com switches endless RESTARTs
+ *
+ *	Revision 1.39  1999/03/08 10:10:52  gklug
+ *	fix: AutoSensing did switch to next mode even if LiPa indicated offline
+ *
+ *	Revision 1.38  1999/03/08 09:49:03  gklug
+ *	fix: Bug using pAC instead of IoC, causing AIX problems
+ *	fix: change compare for Linux compiler bug workaround
+ *
+ *	Revision 1.37  1999/01/28 14:51:33  gklug
+ *	fix: monitor for autosensing and extra RESETS the RX on wire counters
+ *
+ *	Revision 1.36  1999/01/22 09:19:55  gklug
+ *	fix: Init DupMode and InitPauseMd are now called in RxTxEnable
+ *
+ *	Revision 1.35  1998/12/11 15:22:59  gklug
+ *	chg: autosensing: check for receive if manual mode was guessed
+ *	chg: simplified workaround for XMAC errata
+ *	chg: wait additional 100 ms before link goes up.
+ *	chg: autoneg timeout to 600 ms
+ *	chg: restart autoneg even if configured to autonegotiation
+ *
+ *	Revision 1.34  1998/12/10 10:33:14  gklug
+ *	add: more debug messages
+ *	fix: do a new InitPhy if link went down (AutoSensing problem)
+ *	chg: Check for zero shorts if link is NOT up
+ *	chg: reset Port if link goes down
+ *	chg: wait additional 100 ms when link comes up to check shorts
+ *	fix: dummy read extended autoneg status to prevent link going down immediately
+ *
+ *	Revision 1.33  1998/12/07 12:18:29  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *
+ *	Revision 1.32  1998/12/07 07:11:21  gklug
+ *	fix: compiler warning
+ *
+ *	Revision 1.31  1998/12/02 09:29:05  gklug
+ *	fix: WA XMAC Errata: FCSCt check was not correct.
+ *	fix: WA XMAC Errata: Prec Counter were NOT updated in case of short checks.
+ *	fix: Clear Stat : now clears the Prev counters of all known Ports
+ *
+ *	Revision 1.30  1998/12/01 10:54:15  gklug
+ *	dd: workaround for XMAC errata changed. Check RX count and CRC err Count, too.
+ *
+ *	Revision 1.29  1998/12/01 10:01:53  gklug
+ *	fix: if MAC IRQ occurs during port down, this will be handled correctly
+ *
+ *	Revision 1.28  1998/11/26 16:22:11  gklug
+ *	fix: bug in autosense if manual modes are used
+ *
+ *	Revision 1.27  1998/11/26 15:50:06  gklug
+ *	fix: PNMI needs to set PLinkModeConf
+ *
+ *	Revision 1.26  1998/11/26 14:51:58  gklug
+ *	add: AutoSensing functionalty
+ *
+ *	Revision 1.25  1998/11/26 07:34:37  gklug
+ *	fix: Init PrevShorts when restarting port due to Link connection
+ *
+ *	Revision 1.24  1998/11/25 10:57:32  gklug
+ *	fix: remove unreferenced local vars
+ *
+ *	Revision 1.23  1998/11/25 08:26:40  gklug
+ *	fix: don't do a RESET on a starting or stopping port
+ *
+ *	Revision 1.22  1998/11/24 13:29:44  gklug
+ *	add: Workaround for MAC parity errata
+ *
+ *	Revision 1.21  1998/11/18 15:31:06  gklug
+ *	fix: lint bugs
+ *
+ *	Revision 1.20  1998/11/18 12:58:54  gklug
+ *	fix: use PNMI query instead of hardware access
+ *
+ *	Revision 1.19  1998/11/18 12:54:55  gklug
+ *	chg: add new workaround for XMAC Errata
+ *	add: short event counter monitoring on active link too
+ *
+ *	Revision 1.18  1998/11/13 14:27:41  malthoff
+ *	Bug Fix: Packet Arbiter Timeout was not cleared correctly
+ *	for timeout on TX1 and TX2.
+ *
+ *	Revision 1.17  1998/11/04 07:01:59  cgoos
+ *	Moved HW link poll sequence.
+ *	Added call to SkXmRxTxEnable.
+ *
+ *	Revision 1.16  1998/11/03 13:46:03  gklug
+ *	add: functionality of SET_LMODE and SET_FLOW_MODE
+ *	fix: send RLMT LinkDown event when Port stop is given with LinkUp
+ *
+ *	Revision 1.15  1998/11/03 12:56:47  gklug
+ *	fix: Needs more events
+ *
+ *	Revision 1.14  1998/10/30 07:36:35  gklug
+ *	rmv: unnecessary code
+ *
+ *	Revision 1.13  1998/10/29 15:21:57  gklug
+ *	add: Poll link feature for activating HW link
+ *	fix: Deactivate HWLink when Port STOP is given
+ *
+ *	Revision 1.12  1998/10/28 07:38:57  cgoos
+ *	Checking link status at begin of SkHWLinkUp.
+ *
+ *	Revision 1.11  1998/10/22 09:46:50  gklug
+ *	fix SysKonnectFileId typo
+ *
+ *	Revision 1.10  1998/10/14 13:57:47  gklug
+ *	add: Port start/stop event
+ *
+ *	Revision 1.9  1998/10/14 05:48:29  cgoos
+ *	Added definition for Para.
+ *
+ *	Revision 1.8  1998/10/14 05:40:09  gklug
+ *	add: Hardware Linkup signal used
+ *
+ *	Revision 1.7  1998/10/09 06:50:20  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *
+ *	Revision 1.6  1998/10/08 09:11:49  gklug
+ *	add: clear IRQ commands
+ *
+ *	Revision 1.5  1998/10/02 14:27:35  cgoos
+ *	Fixed some typos and wrong event names.
+ *
+ *	Revision 1.4  1998/10/02 06:24:17  gklug
+ *	add: HW error function
+ *	fix: OUT macros
+ *
+ *	Revision 1.3  1998/10/01 07:03:00  gklug
+ *	add: ISR for the usual interrupt source register
+ *
+ *	Revision 1.2  1998/09/03 13:50:33  gklug
+ *	add: function prototypes
+ *
+ *	Revision 1.1  1998/08/27 11:50:21  gklug
+ *	initial revision
+ *
+ *
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+ *	Special Interrupt handler
+ *
+ *	The following abstract should show how this module is included
+ *	in the driver path:
+ *
+ *	In the ISR of the driver the bits for frame transmission complete and
+ *	for receive complete are checked and handled by the driver itself.
+ *	The bits of the slow path mask are checked after that and then the
+ *	entry into the so-called "slow path" is prepared. It is an implementors
+ *	decision whether this is executed directly or just scheduled by
+ *	disabling the mask. In the interrupt service routine some events may be
+ *	generated, so it would be a good idea to call the EventDispatcher
+ *	right after this ISR.
+ *
+ *	The Interrupt source register of the adapter is NOT read by this module.
+ *  SO if the drivers implementor needs a while loop around the
+ *	slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
+ *	each loop entered.
+ *
+ *	However, the MAC Interrupt status registers are read in a while loop.
+ *
+ */
+
+static const char SysKonnectFileId[] =
+	"$Id: skgesirq.c,v 1.83 2003/02/05 15:10:59 rschmidt Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skgepnmi.h"		/* PNMI Definitions */
+#include "h/skrlmt.h"		/* RLMT Definitions */
+#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);
+static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+static void	SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#ifdef OTHER_PHY
+static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int);
+static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int);
+static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* OTHER_PHY */
+
+/*
+ * array of Rx counter from XMAC which are checked
+ * in AutoSense mode to check whether a link is not able to auto-negotiate.
+ */
+static const SK_U16 SkGeRxRegs[]= {
+	XM_RXF_64B,
+	XM_RXF_127B,
+	XM_RXF_255B,
+	XM_RXF_511B,
+	XM_RXF_1023B,
+	XM_RXF_MAX_SZ
+} ;
+
+#ifdef __C2MAN__
+/*
+ *	Special IRQ function
+ *
+ *	General Description:
+ *
+ */
+intro()
+{}
+#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: sets the PLinkMode for HWInit
+ *
+ * Returns: N/A
+ */
+static void SkHWInitDefSense(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		pPrt->PLinkMode = pPrt->PLinkModeConf;
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("AutoSensing: First mode %d on Port %d\n",
+		(int)SK_LMODE_AUTOFULL, Port));
+
+	pPrt->PLinkMode = SK_LMODE_AUTOFULL;
+
+	return;
+}	/* SkHWInitDefSense */
+
+
+/******************************************************************************
+ *
+ *	SkHWSenseGetNext() - Get Next Autosensing Mode
+ *
+ * Description: gets the appropriate next mode
+ *
+ * Note:
+ *
+ */
+SK_U8 SkHWSenseGetNext(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		/* Leave all as configured */
+		return(pPrt->PLinkModeConf);
+	}
+
+	if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) {
+		/* Return next mode AUTOBOTH */
+		return(SK_LMODE_AUTOBOTH);
+	}
+
+	/* Return default autofull */
+	return(SK_LMODE_AUTOFULL);
+}	/* SkHWSenseGetNext */
+
+
+/******************************************************************************
+ *
+ *	SkHWSenseSetNext() - Autosensing Set next mode
+ *
+ * Description:	sets the appropriate next mode
+ *
+ * Returns: N/A
+ */
+void SkHWSenseSetNext(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U8	NewMode)	/* New Mode to be written in sense mode */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("AutoSensing: next mode %d on Port %d\n",
+		(int)NewMode, Port));
+
+	pPrt->PLinkMode = NewMode;
+
+	return;
+}	/* SkHWSenseSetNext */
+
+
+/******************************************************************************
+ *
+ *	SkHWLinkDown() - Link Down handling
+ *
+ * Description: handles the hardware link down signal
+ *
+ * Returns: N/A
+ */
+void SkHWLinkDown(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Disable all MAC interrupts */
+	SkMacIrqDisable(pAC, IoC, Port);
+
+	/* Disable Receiver and Transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
+
+	/* Init default sense mode */
+	SkHWInitDefSense(pAC, IoC, Port);
+
+	if (!pPrt->PHWLinkUp) {
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("Link down Port %d\n", Port));
+
+	/* Set Link to DOWN */
+	pPrt->PHWLinkUp = SK_FALSE;
+
+	/* Reset Port stati */
+	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED;
+
+	/* Re-init Phy especially when the AutoSense default is set now */
+	SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+	/* GP0: used for workaround of Rev. C Errata 2 */
+
+	/* Do NOT signal to RLMT */
+
+	/* Do NOT start the timer here */
+}	/* SkHWLinkDown */
+
+
+/******************************************************************************
+ *
+ *	SkHWLinkUp() - Link Up handling
+ *
+ * Description: handles the hardware link up signal
+ *
+ * Returns: N/A
+ */
+void SkHWLinkUp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		/* We do NOT need to proceed on active link */
+		return;
+	}
+
+	pPrt->PHWLinkUp = SK_TRUE;
+	pPrt->PAutoNegFail = SK_FALSE;
+	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+
+	if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
+	    pPrt->PLinkMode != SK_LMODE_AUTOFULL &&
+	    pPrt->PLinkMode != SK_LMODE_AUTOBOTH) {
+		/* Link is up and no Auto-negotiation should be done */
+
+		/* 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;
+		}
+
+		/* No flow control without auto-negotiation */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+
+		/* enable Rx/Tx */
+		SkMacRxTxEnable(pAC, IoC, Port);
+	}
+}	/* SkHWLinkUp */
+
+
+/******************************************************************************
+ *
+ *	SkMacParity() - MAC parity workaround
+ *
+ * Description: handles MAC parity errors correctly
+ *
+ * Returns: N/A
+ */
+static void SkMacParity(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index of the port failed */
+{
+	SK_EVPARA	Para;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U32		TxMax;		/* TxMax Counter */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Clear IRQ Tx Parity Error */
+	if (pAC->GIni.GIGenesis) {
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
+	}
+	else {
+		/* 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));
+	}
+
+	if (pPrt->PCheckPar) {
+		if (Port == MAC_1) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
+		}
+		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);
+
+		return;
+	}
+
+	/* Check whether frames with a size of 1k were sent */
+	if (pAC->GIni.GIGenesis) {
+		/* Snap statistic counters */
+		(void)SkXmUpdateStats(pAC, IoC, Port);
+
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
+	}
+	else {
+		(void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
+	}
+
+	if (TxMax > 0) {
+		/* From now on check the parity */
+		pPrt->PCheckPar = SK_TRUE;
+	}
+}	/* SkMacParity */
+
+
+/******************************************************************************
+ *
+ *	SkGeHwErr() - Hardware Error service routine
+ *
+ * Description: handles all HW Error interrupts
+ *
+ * Returns: N/A
+ */
+static void SkGeHwErr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	HwStatus)	/* Interrupt status word */
+{
+	SK_EVPARA	Para;
+	SK_U16		Word;
+
+	if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
+		/* PCI Errors occured */
+		if ((HwStatus & IS_IRQ_STAT) != 0) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
+		}
+
+		/* Reset all bits in the PCI STATUS register */
+		SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	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 */
+		/* This is necessary only for Rx timing measurements */
+		if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+			/* 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);
+		}
+	}
+
+	if ((HwStatus & IS_RAM_RD_PAR) != 0) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if ((HwStatus & IS_RAM_WR_PAR) != 0) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if ((HwStatus & IS_M1_PAR_ERR) != 0) {
+		SkMacParity(pAC, IoC, MAC_1);
+	}
+
+	if ((HwStatus & IS_M2_PAR_ERR) != 0) {
+		SkMacParity(pAC, IoC, MAC_2);
+	}
+
+	if ((HwStatus & IS_R1_PAR_ERR) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
+
+		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);
+	}
+
+	if ((HwStatus & IS_R2_PAR_ERR) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
+
+		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);
+	}
+}	/* SkGeHwErr */
+
+
+/******************************************************************************
+ *
+ *	SkGeSirqIsr() - Special Interrupt Service Routine
+ *
+ * Description: handles all non data transfer specific interrupts (slow path)
+ *
+ * Returns: N/A
+ */
+void SkGeSirqIsr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	Istatus)	/* Interrupt status word */
+{
+	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) {
+		/* read the HW Error Interrupt source */
+		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+		SkGeHwErr(pAC, IoC, RegVal32);
+	}
+
+	/*
+	 * Packet Timeout interrupts
+	 */
+	/* Check whether MACs are correctly initialized */
+	if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
+		pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
+		/* MAC 1 was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
+			SKERR_SIRQ_E004MSG);
+	}
+
+	if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
+	    pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
+		/* MAC 2 was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
+			SKERR_SIRQ_E005MSG);
+	}
+
+	if ((Istatus & IS_PA_TO_RX1) != 0) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
+			SKERR_SIRQ_E002MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
+	}
+
+	if ((Istatus & IS_PA_TO_RX2) != 0) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
+			SKERR_SIRQ_E003MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
+	}
+
+	if ((Istatus & IS_PA_TO_TX1) != 0) {
+
+		pPrt = &pAC->GIni.GP[0];
+
+		/* 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) {
+			/*
+			 * many more pack. arb. timeouts may come in between,
+			 * we ignore those
+			 */
+			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, 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);
+		}
+	}
+
+	if ((Istatus & IS_PA_TO_TX2) != 0) {
+
+		pPrt = &pAC->GIni.GP[1];
+
+		/* 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);
+		}
+	}
+
+	/* Check interrupts of the particular queues */
+	if ((Istatus & IS_R1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
+			SKERR_SIRQ_E006MSG);
+		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);
+	}
+
+	if ((Istatus & IS_R2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
+			SKERR_SIRQ_E007MSG);
+		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);
+	}
+
+	if ((Istatus & IS_XS1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
+			SKERR_SIRQ_E008MSG);
+		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);
+	}
+
+	if ((Istatus & IS_XA1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
+			SKERR_SIRQ_E009MSG);
+		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);
+	}
+
+	if ((Istatus & IS_XS2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
+			SKERR_SIRQ_E010MSG);
+		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);
+	}
+
+	if ((Istatus & IS_XA2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
+			SKERR_SIRQ_E011MSG);
+		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);
+	}
+
+	/* External reg interrupt */
+	if ((Istatus & IS_EXT_REG) != 0) {
+		/* Test IRQs from PHY */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			pPrt = &pAC->GIni.GP[i];
+
+			if (pPrt->PState == SK_PRT_RESET) {
+				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);
+				}
+				break;
+
+			case SK_PHY_MARV_COPPER:
+			case SK_PHY_MARV_FIBER:
+				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
+				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_MASK, &PhyIMsk);
+
+				if ((PhyInt & PhyIMsk) != 0) {
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Port %d Marv Int: 0x%04X Mask: 0x%04X\n",
+						i, PhyInt, PhyIMsk));
+					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 */
+			}
+		}
+	}
+
+	/* I2C Ready interrupt */
+	if ((Istatus & IS_I2C_READY) != 0) {
+		SkI2cIsr(pAC, IoC);
+	}
+
+	if ((Istatus & IS_LNK_SYNC_M1) != 0) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if ((Istatus & IS_MAC1) != 0) {
+		/* IRQ from MAC 1 */
+		SkMacIrq(pAC, IoC, MAC_1);
+	}
+
+	if ((Istatus & IS_LNK_SYNC_M2) != 0) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if ((Istatus & IS_MAC2) != 0) {
+		/* IRQ from MAC 2 */
+		SkMacIrq(pAC, IoC, MAC_2);
+	}
+
+	/* Timer interrupt (served last) */
+	if ((Istatus & IS_TIMINT) != 0) {
+		SkHwtIsr(pAC, IoC);
+	}
+}	/* SkGeSirqIsr */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ */
+static int	SkGePortCheckShorts(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	SK_U32		Shorts;			/* Short Event Counter */
+	SK_U32		CheckShorts;	/* Check value for Short Event Counter */
+	SK_U64		RxCts;			/* Rx Counter (packets on network) */
+	SK_U32		RxTmp;			/* Rx temp. Counter */
+	SK_U32		FcsErrCts;		/* FCS Error Counter */
+	SK_GEPORT	*pPrt;			/* GIni Port struct pointer */
+	int			Rtv;			/* Return value */
+	int			i;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Default: no action */
+	Rtv = SK_HW_PS_NONE;
+
+	(void)SkXmUpdateStats(pAC, IoC, Port);
+
+	/* Extra precaution: check for short Event counter */
+	(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+
+	/*
+	 * Read Rx counter (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;
+	}
+
+	/* On default: check shorts against zero */
+	CheckShorts = 0;
+
+	/* Extra precaution on active links */
+	if (pPrt->PHWLinkUp) {
+		/* Reset Link Restart counter */
+		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
+
+		/* If link is up check for 2 */
+		CheckShorts = 2;
+
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
+
+		if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+		    pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
+		    (pPrt->PLinkMode == SK_LMODE_HALF ||
+			 pPrt->PLinkMode == SK_LMODE_FULL)) {
+			/*
+			 * This is autosensing and we are in the fallback
+			 * manual full/half duplex mode.
+			 */
+			if (RxCts == pPrt->PPrevRx) {
+				/* Nothing received, restart link */
+				pPrt->PPrevFcs = FcsErrCts;
+				pPrt->PPrevShorts = Shorts;
+
+				return(SK_HW_PS_RESTART);
+			}
+			else {
+				pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
+			}
+		}
+
+		if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
+		    (!(FcsErrCts - pPrt->PPrevFcs))) {
+			/*
+			 * Note: The compare with zero above has to be done the way shown,
+			 * otherwise the Linux driver will have a problem.
+			 */
+			/*
+			 * We received a bunch of frames or no CRC error occured on the
+			 * network -> ok.
+			 */
+			pPrt->PPrevRx = RxCts;
+			pPrt->PPrevFcs = FcsErrCts;
+			pPrt->PPrevShorts = Shorts;
+
+			return(SK_HW_PS_NONE);
+		}
+
+		pPrt->PPrevFcs = FcsErrCts;
+	}
+
+
+	if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Short Event Count Restart Port %d \n", Port));
+		Rtv = SK_HW_PS_RESTART;
+	}
+
+	pPrt->PPrevShorts = Shorts;
+	pPrt->PPrevRx = RxCts;
+
+	return(Rtv);
+}	/* SkGePortCheckShorts */
+
+
+/******************************************************************************
+ *
+ * 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(
+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));
+#ifdef OTHER_PHY
+	case SK_PHY_LONE:
+		return(SkGePortCheckUpLone(pAC, IoC, Port));
+	case SK_PHY_NAT:
+		return(SkGePortCheckUpNat(pAC, IoC, Port));
+#endif /* OTHER_PHY */
+	}
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUp */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpXmac(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	SK_U32		Shorts;		/* Short Event Counter */
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U32		GpReg;		/* General Purpose register value */
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		IsrcSum;	/* Interrupt source register sum */
+	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];
+
+	if (pPrt->PHWLinkUp) {
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			return(SK_HW_PS_NONE);
+		}
+		else {
+			return(SkGePortCheckShorts(pAC, IoC, Port));
+		}
+	}
+
+	IsrcSum = pPrt->PIsave;
+	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);
+
+		if ((GpReg & XM_GP_INP_ASS) == 0) {
+			/* The Link is in sync */
+			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 */
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Link in sync Restart Port %d\n", Port));
+
+				(void)SkXmUpdateStats(pAC, IoC, Port);
+
+				/* We now need to reinitialize the PrevShorts counter */
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+				pPrt->PPrevShorts = Shorts;
+
+				pPrt->PLinkBroken = SK_FALSE;
+
+				/*
+				 * Link Restart Workaround:
+				 *  it may be possible that the other Link side
+				 *  restarts its link as well an we detect
+				 *  another LinkBroken. To prevent this
+				 *  happening we check for a maximum number
+				 *  of consecutive restart. If those happens,
+				 *  we do NOT restart the active link and
+				 *  check whether the link is now o.k.
+				 */
+				pPrt->PLinkResCt++;
+
+				pPrt->PAutoNegTimeOut = 0;
+
+				if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
+					return(SK_HW_PS_RESTART);
+				}
+
+				pPrt->PLinkResCt = 0;
+
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
+			}
+			else {
+				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));
+
+				/* Do nothing more if link is broken */
+				return(SK_HW_PS_NONE);
+			}
+		}
+		else {
+			/* Do nothing more if link is broken */
+			return(SK_HW_PS_NONE);
+		}
+
+	}
+	else {
+		/* Link was not broken, check if it is */
+		XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+		IsrcSum |= Isrc;
+		if ((Isrc & XM_IS_INP_ASS) != 0) {
+			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+			IsrcSum |= Isrc;
+			if ((Isrc & XM_IS_INP_ASS) != 0) {
+				XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+				IsrcSum |= Isrc;
+				if ((Isrc & XM_IS_INP_ASS) != 0) {
+					pPrt->PLinkBroken = SK_TRUE;
+					/* Re-Init Link partner Autoneg flag */
+					pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Link broken Port %d\n", Port));
+
+					/* Cable removed-> reinit sense mode */
+					SkHWInitDefSense(pAC, IoC, Port);
+
+					return(SK_HW_PS_RESTART);
+				}
+			}
+		}
+		else {
+			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+			if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
+				return(SK_HW_PS_RESTART);
+			}
+		}
+	}
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * auto-negotiation is done.
+	 */
+	XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+	IsrcSum |= Isrc;
+
+	SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+
+	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 = (SK_U16)(IsrcSum & XM_IS_AND);
+		}
+#ifdef DEBUG
+		if ((pPrt->PIsave & XM_IS_AND) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
+	}
+
+	if (AutoNeg) {
+		if ((IsrcSum & XM_IS_AND) != 0) {
+			SkHWLinkUp(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
+					 Port, LpAb, ResAb));
+
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port);
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+				}
+
+				return(SK_HW_PS_RESTART);
+			}
+			/*
+			 * Dummy Read extended status to prevent extra link down/ups
+			 * (clear Page Received bit if set)
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done Port %d\n", Port));
+			return(SK_HW_PS_LINK);
+		}
+
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/* Increase the Timeout counter */
+			pPrt->PAutoNegTOCt++;
+
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/* Set Link manually up */
+				SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n", Port));
+			}
+
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
+				pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
+				/*
+				 * This is rather complicated.
+				 * we need to check here whether the LIPA_AUTO
+				 * we saw before is false alert. We saw at one
+				 * switch ( SR8800) that on boot time it sends
+				 * just one auto-neg packet and does no further
+				 * auto-negotiation.
+				 * Solution: we restart the autosensing after
+				 * a few timeouts.
+				 */
+				pPrt->PAutoNegTOCt = 0;
+				pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+				SkHWInitDefSense(pAC, IoC, Port);
+			}
+
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
+		}
+	}
+	else {
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+
+		/*
+		 * Link sync (GP) and so assume a good connection. But if not received
+		 * a bunch of frames received in a time slot (maybe broken tx cable)
+		 * the port is restart.
+		 */
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpXmac */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	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_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		PhyStat;	/* Phy Status Register */
+	SK_U16		ResAb;		/* Master/Slave resolution */
+	SK_U16		Ctrl;		/* Broadcom control flags */
+#ifdef DEBUG
+	SK_U16		LpAb;
+	SK_U16		ExtStat;
+#endif /* DEBUG */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Check for No HCD Link events (#10523) */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
+
+#ifdef xDEBUG
+	if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT) ==
+		(PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
+
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1 - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#endif /* DEBUG */
+
+	if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
+		/*
+		 * Workaround BCom Errata:
+		 *	enable and disable loopback mode if "NO HCD" occurs.
+		 */
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl | PHY_CT_LOOP));
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl & ~PHY_CT_LOOP));
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("No HCD Link event, Port %d\n", Port));
+#ifdef xDEBUG
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"No HCD link event, port %d.",
+			(void *)Port,
+			(void *)NULL);
+#endif /* DEBUG */
+	}
+
+	/* Not obsolete: link status bit is latched to 0 and autoclearing! */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+#ifdef xDEBUG
+	{
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1a - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+		Stat1 = Stat1 << 16 | PhyStat;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+		Stat2 = Stat2 << 16 | ResAb;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#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.
+	 */
+
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
+
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		/* 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_HW_PS_RESTART);
+	}
+
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		return(SK_HW_PS_NONE);
+	}
+
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		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));
+
+	if (AutoNeg) {
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+			SkHWLinkUp(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			if (Done != SK_AND_OK) {
+#ifdef DEBUG
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					Port, LpAb, ExtStat));
+#endif /* DEBUG */
+				return(SK_HW_PS_RESTART);
+			}
+			else {
+#ifdef xDEBUG
+				/* Dummy read ISR to prevent extra link downs/ups */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+				if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+					CMSMPrintString(
+						pAC->pConfigTable,
+						MSG_TYPE_RUNTIME_INFO,
+						"CheckUp2 - Stat: %x",
+						(void *)ExtStat,
+						(void *)NULL);
+				}
+#endif /* DEBUG */
+
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg done Port %d\n", Port));
+				return(SK_HW_PS_LINK);
+			}
+		}
+	}
+	else {	/* !AutoNeg */
+		/* Link is up and we don't need more. */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+#ifdef xDEBUG
+		/* Dummy read ISR to prevent extra link downs/ups */
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+		if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+			CMSMPrintString(
+				pAC->pConfigTable,
+				MSG_TYPE_RUNTIME_INFO,
+				"CheckUp3 - Stat: %x",
+				(void *)ExtStat,
+				(void *)NULL);
+		}
+#endif /* DEBUG */
+
+		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 */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	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_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		ResAb;		/* Master/Slave resolution */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Read PHY Interrupt Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &Isrc);
+
+	if ((Isrc & PHY_M_IS_AN_COMPL) != 0) {
+		/* TBD */
+	}
+
+	if ((Isrc & PHY_M_IS_DOWNSH_DET) != 0) {
+		/* TBD */
+	}
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+	/* 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;
+	}
+
+	/* 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));
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		/* 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_HW_PS_RESTART);
+	}
+
+	/* Read PHY Specific Status */
+	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));
+
+	if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
+		return(SK_HW_PS_NONE);
+	}
+
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+
+	pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
+
+	if (AutoNeg) {
+		/* Auto-Negotiation Over ? */
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+
+			SkHWLinkUp(pAC, IoC, Port);
+
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+
+			if (Done != SK_AND_OK) {
+				return(SK_HW_PS_RESTART);
+			}
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done Port %d\n", Port));
+			return(SK_HW_PS_LINK);
+		}
+	}
+	else {	/* !AutoNeg */
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync, Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpGmac */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpLone(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	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];
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+	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.
+	 */
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
+	StatSum |= PhyStat;
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		/* Save Auto-negotiation Done bit */
+		pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
+#ifdef DEBUG
+		if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
+	}
+
+	if (AutoNeg) {
+		if ((StatSum & PHY_ST_AN_OVER) != 0) {
+			SkHWLinkUp(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					 Port, LpAb, ExtStat));
+
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port);
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+				}
+
+				return(SK_HW_PS_RESTART);
+
+			}
+			else {
+				/*
+				 * Dummy Read interrupt status to prevent
+				 * extra link down/ups
+				 */
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg done Port %d\n", Port));
+				return(SK_HW_PS_LINK);
+			}
+		}
+
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/* Set Link manually up */
+				SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n", Port));
+			}
+
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
+		}
+	}
+	else {
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Dummy Read interrupt status to prevent
+		 * extra link down/ups
+		 */
+		SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+
+		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);
+}	/* SkGePortCheckUpLone */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpNat() - Check if the link is up on National PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpNat(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	/* todo: National */
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkGeSirqEvent() - Event Service Routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+int	SkGeSirqEvent(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+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;
+	int			PortStat;
+	SK_U8		Val8;
+
+	Port = Para.Para32[0];
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (Event) {
+	case SK_HWEV_WATIM:
+		/* Check whether port came up */
+		PortStat = SkGePortCheckUp(pAC, IoC, Port);
+
+		switch (PortStat) {
+		case SK_HW_PS_RESTART:
+			if (pPrt->PHWLinkUp) {
+				/*
+				 * Set Link to down.
+				 */
+				SkHWLinkDown(pAC, IoC, Port);
+
+				/*
+				 * Signal directly to RLMT to ensure correct
+				 * sequence of SWITCH and RESET event.
+				 */
+				SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+			}
+
+			/* Restart needed */
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+			break;
+
+		case SK_HW_PS_LINK:
+			/* 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;
+		}
+		else {
+			Time = SK_WA_INA_TIME;
+		}
+
+		/* Todo: still needed for non-XMAC PHYs??? */
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Time,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+		break;
+
+	case SK_HWEV_PORT_START:
+		if (pPrt->PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Schedule Port RESET */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+		break;
+
+	case SK_HWEV_PORT_STOP:
+		if (pPrt->PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+
+		/* Stop Workaround Timer */
+		SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
+
+		SkHWLinkDown(pAC, IoC, Port);
+		break;
+
+	case SK_HWEV_UPDATE_STAT:
+		/* We do NOT need to update any statistics */
+		break;
+
+	case SK_HWEV_CLEAR_STAT:
+		/* We do NOT need to clear any statistics */
+		for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
+			pPrt->PPrevRx = 0;
+			pPrt->PPrevFcs = 0;
+			pPrt->PPrevShorts = 0;
+		}
+		break;
+
+	case SK_HWEV_SET_LMODE:
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkModeConf != Val8) {
+			/* Set New link mode */
+			pPrt->PLinkModeConf = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_FLOWMODE:
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PFlowCtrlMode != Val8) {
+			/* Set New Flow Control mode */
+			pPrt->PFlowCtrlMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_ROLE:
+		/* not possible for fiber */
+		if (!pAC->GIni.GICopperType) {
+			break;
+		}
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PMSMode != Val8) {
+			/* Set New link mode */
+			pPrt->PMSMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_SPEED:
+		if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+			break;
+		}
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkSpeed != Val8) {
+			/* Set New Speed parameter */
+			pPrt->PLinkSpeed = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	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);
+			}
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
+		break;
+	}
+
+	return(0);
+}	/* SkGeSirqEvent */
+
+
+/******************************************************************************
+ *
+ *	SkPhyIsrBcom() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from BCom PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrBcom(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_EVPARA	Para;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if ((IStatus & PHY_B_IS_PSE) != 0) {
+		/* Incorrectable pair swap error */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | 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);
+
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+	}
+
+}	/* SkPhyIsrBcom */
+
+
+/******************************************************************************
+ *
+ *	SkPhyIsrGmac() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from Marvell PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrGmac(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_EVPARA	Para;
+
+	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);
+
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
+		/* Auto-Negotiation Error */
+		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 */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkPhyIsrLone() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from LONE PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrLone(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* Io Context */
+int		Port,		/* Port Num = PHY Num */
+SK_U16	IStatus)	/* Interrupt Status */
+{
+	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;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+}	/* SkPhyIsrLone */
+#endif /* OTHER_PHY */
+
+#endif /* CONFIG_SK98 */
+
+/* End of File */
diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c
new file mode 100644
index 0000000..2ab635a
--- /dev/null
+++ b/drivers/net/sk98lin/ski2c.c
@@ -0,0 +1,1505 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.57 $
+ * Date:	$Date: 2003/01/28 09:17:38 $
+ * Purpose:	Functions to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: ski2c.c,v $
+ *	Revision 1.57  2003/01/28 09:17:38  rschmidt
+ *	Fixed handling for sensors on YUKON Fiber.
+ *	Editorial changes.
+ *
+ *	Revision 1.56  2002/12/19 14:20:41  rschmidt
+ *	Added debugging code in SkI2cWait().
+ *	Replaced all I2C-write operations with function SkI2cWrite().
+ *	Fixed compiler warning because of uninitialized 'Time' in SkI2cEvent().
+ *	Editorial changes.
+ *
+ *	Revision 1.55  2002/10/15 07:23:55  rschmidt
+ *	Added setting of the GIYukon32Bit bool variable to distinguish
+ *	32-bit adapters.
+ *	Editorial changes (TWSI).
+ *
+ *	Revision 1.54  2002/08/13 09:05:06  rschmidt
+ *	Added new thresholds if VAUX is not available (GIVauxAvail).
+ *	Merged defines for PHY PLL 3V3 voltage (A and B).
+ *	Editorial changes.
+ *
+ *	Revision 1.53  2002/08/08 11:04:53  rwahl
+ *	Added missing comment for revision 1.51
+ *
+ *	Revision 1.52  2002/08/08 10:09:02  jschmalz
+ *	Sensor init state caused wrong error log entry
+ *
+ *	Revision 1.51  2002/08/06 09:43:03  jschmalz
+ *	Extensions and changes for Yukon
+ *
+ *	Revision 1.50  2002/08/02 12:09:22  rschmidt
+ *	Added support for YUKON sensors.
+ *	Editorial changes.
+ *
+ *	Revision 1.49  2002/07/30 11:07:52  rschmidt
+ *	Replaced MaxSens init by update for Copper in SkI2cInit1(),
+ *	because it was already initialized in SkI2cInit0().
+ *	Editorial changes.
+ *
+ *	Revision 1.48  2001/08/16 12:44:33  afischer
+ *	LM80 sensor init values corrected
+ *
+ *	Revision 1.47  2001/04/05 11:38:09  rassmann
+ *	Set SenState to idle in SkI2cWaitIrq().
+ *	Changed error message in SkI2cWaitIrq().
+ *
+ *	Revision 1.46  2001/04/02 14:03:35  rassmann
+ *	Changed pAC to IoC in SK_IN32().
+ *
+ *	Revision 1.45  2001/03/21 12:12:49  rassmann
+ *	Resetting I2C_READY interrupt in SkI2cInit1().
+ *
+ *	Revision 1.44  2000/08/07 15:49:03  gklug
+ *	Fix: SK_INFAST only in NetWare driver.
+ *
+ *	Revision 1.43  2000/08/03 14:28:17  rassmann
+ *	Added function to wait for I2C being ready before resetting the board.
+ *	Replaced one duplicate "out of range" message with correct one.
+ *
+ *	Revision 1.42  1999/11/22 13:35:12  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.41  1999/09/14 14:11:30  malthoff
+ *	The 1000BT Dual Link adapter has got only one Fan.
+ *	The second Fan has been removed.
+ *
+ *	Revision 1.40  1999/05/27 13:37:27  malthoff
+ *	Set divisor of 1 for fan count calculation.
+ *
+ *	Revision 1.39  1999/05/20 14:54:43  malthoff
+ *	I2c.DummyReads is not used in Diagnostics.
+ *
+ *	Revision 1.38  1999/05/20 09:20:56  cgoos
+ *	Changes for 1000Base-T (up to 9 sensors and fans).
+ *
+ *	Revision 1.37  1999/03/25 15:11:36  gklug
+ *	fix: reset error flag if sensor reads correct value
+ *
+ *	Revision 1.36  1999/01/07 14:11:16  gklug
+ *	fix: break added
+ *
+ *	Revision 1.35  1999/01/05 15:31:49  gklug
+ *	fix: CLEAR STAT command is now added correctly
+ *
+ *	Revision 1.34  1998/12/01 13:45:16  gklug
+ *	fix: introduced Init level, because we don't need reinits
+ *
+ *	Revision 1.33  1998/11/09 14:54:25  malthoff
+ *	Modify I2C Transfer Timeout handling for Diagnostics.
+ *
+ *	Revision 1.32  1998/11/03 06:54:35  gklug
+ *	fix: Need dummy reads at the beginning to init sensors
+ *
+ *	Revision 1.31  1998/11/03 06:42:42  gklug
+ *	fix: select correctVIO range only if between warning levels
+ *
+ *	Revision 1.30  1998/11/02 07:36:53  gklug
+ *	fix: Error should not include WARNING message
+ *
+ *	Revision 1.29  1998/10/30 15:07:43  malthoff
+ *	Disable 'I2C does not compelete' error log for diagnostics.
+ *
+ *	Revision 1.28  1998/10/22 09:48:11  gklug
+ *	fix: SysKonnectFileId typo
+ *
+ *	Revision 1.27  1998/10/20 09:59:46  gklug
+ *	add: parameter to SkOsGetTime
+ *
+ *	Revision 1.26  1998/10/09 06:10:59  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *
+ *	Revision 1.25  1998/09/08 12:40:26  gklug
+ *	fix: syntax error in if clause
+ *
+ *	Revision 1.24  1998/09/08 12:19:42  gklug
+ *	chg: INIT Level checking
+ *
+ *	Revision 1.23  1998/09/08 07:37:20  gklug
+ *	fix: log error if PCI_IO voltage sensor could not be initialized
+ *
+ *	Revision 1.22  1998/09/04 08:30:03  malthoff
+ *	Bugfixes during SK_DIAG testing:
+ *	- correct NS2BCLK() macro
+ *	- correct SkI2cSndDev()
+ *	- correct SkI2cWait() loop waiting for an event
+ *
+ *	Revision 1.21  1998/08/27 14:46:01  gklug
+ *	chg: if-then-else replaced by switch
+ *
+ *	Revision 1.20  1998/08/27 14:40:07  gklug
+ *	test: integral types
+ *
+ *	Revision 1.19  1998/08/25 07:51:54  gklug
+ *	fix: typos for compiling
+ *
+ *	Revision 1.18  1998/08/25 06:12:24  gklug
+ *	add: count errors and warnings
+ *	fix: check not the sensor state but the ErrFlag!
+ *
+ *	Revision 1.17  1998/08/25 05:56:48  gklug
+ *	add: CheckSensor function
+ *
+ *	Revision 1.16  1998/08/20 11:41:10  gklug
+ *	chg: omit STRCPY macro by using char * as Sensor Description
+ *
+ *	Revision 1.15  1998/08/20 11:37:35  gklug
+ *	chg: change Ioc to IoC
+ *
+ *	Revision 1.14  1998/08/20 11:32:52  gklug
+ *	fix: Para compile error
+ *
+ *	Revision 1.13  1998/08/20 11:27:41  gklug
+ *	fix: Compile bugs with new awrning constants
+ *
+ *	Revision 1.12  1998/08/20 08:53:05  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *
+ *	Revision 1.11  1998/08/19 12:39:22  malthoff
+ *	Compiler Fix: Some names have changed.
+ *
+ *	Revision 1.10  1998/08/19 12:20:56  gklug
+ *	fix: remove struct from C files (see CCC)
+ *
+ *	Revision 1.9  1998/08/19 06:28:46  malthoff
+ *	SkOsGetTime returns SK_U64 now.
+ *
+ *	Revision 1.8  1998/08/17 13:53:33  gklug
+ *	fix: Parameter of event function and its result
+ *
+ *	Revision 1.7  1998/08/17 07:02:15  malthoff
+ *	Modify the functions for accessing the I2C SW Registers.
+ *	Modify SkI2cWait().
+ *	Put Lm80RcvReg into sklm80.c
+ *	Remove Compiler Errors.
+ *
+ *	Revision 1.6  1998/08/14 07:13:20  malthoff
+ *	remove pAc with pAC
+ *	remove smc with pAC
+ *	change names to new convention
+ *
+ *	Revision 1.5  1998/08/14 06:24:49  gklug
+ *	add: init level 1 and 2
+ *
+ *	Revision 1.4  1998/08/12 14:31:12  gklug
+ *	add: error log for unknown event
+ *
+ *	Revision 1.3  1998/08/12 13:37:04  gklug
+ *	add: Init 0 function
+ *
+ *	Revision 1.2  1998/08/11 07:27:15  gklug
+ *	add: functions of the interface
+ *	adapt rest of source to C coding Conventions
+ *	rmv: unnecessary code taken from Mona Lisa
+ *
+ *	Revision 1.1  1998/06/19 14:28:43  malthoff
+ *	Created. Sources taken from ML Projekt.
+ *	Sources have to be reworked for GE.
+ *
+ *
+ ******************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+ *	I2C Protocol
+ */
+static const char SysKonnectFileId[] =
+	"$Id: ski2c.c,v 1.57 2003/01/28 09:17:38 rschmidt Exp $";
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	I2C protocol implementation.
+
+	General Description:
+
+	The I2C protocol is used for the temperature sensors and for
+	the serial EEPROM which hold the configuration.
+
+	This file covers functions that allow to read write and do
+	some bulk requests a specified I2C address.
+
+	The Genesis has 2 I2C buses. One for the EEPROM which holds
+	the VPD Data and one for temperature and voltage sensor.
+	The following picture shows the I2C buses, I2C devices and
+	their control registers.
+
+	Note: The VPD functions are in skvpd.c
+.
+.	PCI Config I2C Bus for VPD Data:
+.
+.		      +------------+
+.		      | VPD EEPROM |
+.		      +------------+
+.			     |
+.			     | <-- I2C
+.			     |
+.		 +-----------+-----------+
+.		 |			 |
+.	+-----------------+	+-----------------+
+.	| PCI_VPD_ADR_REG |	| PCI_VPD_DAT_REG |
+.	+-----------------+	+-----------------+
+.
+.
+.	I2C Bus for LM80 sensor:
+.
+.			+-----------------+
+.			| Temperature and |
+.			| Voltage Sensor  |
+.			| 	LM80	  |
+.			+-----------------+
+.				|
+.				|
+.			I2C --> |
+.				|
+.			     +----+
+.	     +-------------->| OR |<--+
+.	     |		     +----+   |
+.     +------+------+		      |
+.     |		    |		      |
+. +--------+	+--------+	+----------+
+. | B2_I2C |	| B2_I2C |	|  B2_I2C  |
+. | _CTRL  |	| _DATA  |	|   _SW    |
+. +--------+	+--------+	+----------+
+.
+	The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL
+	and B2_I2C_DATA registers.
+	For driver software it is recommended to use the I2C control and
+	data register, because I2C bus timing is done by the ASIC and
+	an interrupt may be received when the I2C request is completed.
+
+	Clock Rate Timing:			MIN	MAX	generated by
+		VPD EEPROM:			50 kHz	100 kHz		HW
+		LM80 over I2C Ctrl/Data reg.	50 kHz	100 kHz		HW
+		LM80 over B2_I2C_SW register	0	400 kHz		SW
+
+	Note:	The clock generated by the hardware is dependend on the
+		PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD
+		clock is 50 kHz.
+ */
+intro()
+{}
+#endif
+
+#ifdef	SK_DIAG
+/*
+ * I2C Fast Mode timing values used by the LM80.
+ * If new devices are added to the I2C bus the timing values have to be checked.
+ */
+#ifndef I2C_SLOW_TIMING
+#define	T_CLK_LOW			1300L	/* clock low time in ns */
+#define	T_CLK_HIGH		 	 600L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 100L	/* data in Set-up Time */
+#define T_START_HOLD		 600L	/* start condition hold time */
+#define T_START_SETUP		 600L	/* start condition Set-up time */
+#define	T_STOP_SETUP		 600L	/* stop condition Set-up time */
+#define T_BUS_IDLE			1300L	/* time the bus must free after Tx */
+#define	T_CLK_2_DATA_OUT	 900L	/* max. clock low to data output valid */
+#else	/* I2C_SLOW_TIMING */
+/* I2C Standard Mode Timing */
+#define	T_CLK_LOW			4700L	/* clock low time in ns */
+#define	T_CLK_HIGH			4000L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 250L	/* data in Set-up Time */
+#define T_START_HOLD		4000L	/* start condition hold time */
+#define T_START_SETUP		4700L	/* start condition Set-up time */
+#define	T_STOP_SETUP		4000L	/* stop condition Set-up time */
+#define T_BUS_IDLE			4700L	/* time the bus must free after Tx */
+#endif	/* !I2C_SLOW_TIMING */
+
+#define NS2BCLK(x)	(((x)*125)/10000)
+
+/*
+ * I2C Wire Operations
+ *
+ * About I2C_CLK_LOW():
+ *
+ * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting
+ * clock to low, to prevent the ASIC and the I2C data client from driving the
+ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client
+ * send an 'ACK'). See also Concentrator Bugreport No. 10192.
+ */
+#define I2C_DATA_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA)
+#define	I2C_DATA_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA)
+#define	I2C_DATA_OUT(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA_DIR)
+#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA)
+#define	I2C_CLK_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_CLK)
+#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR)
+#define	I2C_START_COND(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK)
+
+#define NS2CLKT(x)	((x*125L)/10000)
+
+/*--------------- I2C Interface Register Functions --------------- */
+
+/*
+ * sending one bit
+ */
+void SkI2cSndBit(
+SK_IOC	IoC,	/* I/O Context */
+SK_U8	Bit)	/* Bit to send */
+{
+	I2C_DATA_OUT(IoC);
+	if (Bit) {
+		I2C_DATA_HIGH(IoC);
+	}
+	else {
+		I2C_DATA_LOW(IoC);
+	}
+	SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP));
+	I2C_CLK_HIGH(IoC);
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+	I2C_CLK_LOW(IoC);
+}	/* SkI2cSndBit*/
+
+
+/*
+ * Signal a start to the I2C Bus.
+ *
+ * A start is signaled when data goes to low in a high clock cycle.
+ *
+ * Ends with Clock Low.
+ *
+ * Status: not tested
+ */
+void SkI2cStart(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data high */
+	I2C_DATA_OUT(IoC);
+	I2C_DATA_HIGH(IoC);
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP));
+
+	/* Set Data Low */
+	I2C_DATA_LOW(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD));
+
+	/* Clock low without Data to Input */
+	I2C_START_COND(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW));
+}	/* SkI2cStart */
+
+
+void SkI2cStop(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data low */
+	I2C_DATA_OUT(IoC);
+	I2C_DATA_LOW(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP));
+
+	/*
+	 * Set Data High:	Do it by setting the Data Line to Input.
+	 *			Because of a pull up resistor the Data Line
+	 *			floods to high.
+	 */
+	I2C_DATA_IN(IoC);
+
+	/*
+	 *	When I2C activity is stopped
+	 *	 o	DATA should be set to input and
+	 *	 o	CLOCK should be set to high!
+	 */
+	SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE));
+}	/* SkI2cStop */
+
+
+/*
+ * Receive just one bit via the I2C bus.
+ *
+ * Note:	Clock must be set to LOW before calling this function.
+ *
+ * Returns The received bit.
+ */
+int SkI2cRcvBit(
+SK_IOC	IoC)	/* I/O Context */
+{
+	int	Bit;
+	SK_U8	I2cSwCtrl;
+
+	/* Init data as input line */
+	I2C_DATA_IN(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+
+	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+	Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0;
+
+	I2C_CLK_LOW(IoC);
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT));
+
+	return(Bit);
+}	/* SkI2cRcvBit */
+
+
+/*
+ * Receive an ACK.
+ *
+ * returns	0 If acknowledged
+ *		1 in case of an error
+ */
+int SkI2cRcvAck(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	return(SkI2cRcvBit(IoC) != 0);
+}	/* SkI2cRcvAck */
+
+
+/*
+ * Send an NACK.
+ */
+void SkI2cSndNAck(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	SkI2cSndBit(IoC, 1);
+}	/* SkI2cSndNAck */
+
+
+/*
+ * Send an ACK.
+ */
+void SkI2cSndAck(
+SK_IOC IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 *
+	 */
+	SkI2cSndBit(IoC, 0);
+}	/* SkI2cSndAck */
+
+
+/*
+ * Send one byte to the I2C device and wait for ACK.
+ *
+ * Return acknowleged status.
+ */
+int SkI2cSndByte(
+SK_IOC	IoC,	/* I/O Context */
+int		Byte)	/* byte to send */
+{
+	int	i;
+
+	for (i = 0; i < 8; i++) {
+		if (Byte & (1<<(7-i))) {
+			SkI2cSndBit(IoC, 1);
+		}
+		else {
+			SkI2cSndBit(IoC, 0);
+		}
+	}
+
+	return(SkI2cRcvAck(IoC));
+}	/* SkI2cSndByte */
+
+
+/*
+ * Receive one byte and ack it.
+ *
+ * Return byte.
+ */
+int SkI2cRcvByte(
+SK_IOC	IoC,	/* I/O Context */
+int		Last)	/* Last Byte Flag */
+{
+	int	i;
+	int	Byte = 0;
+
+	for (i = 0; i < 8; i++) {
+		Byte <<= 1;
+		Byte |= SkI2cRcvBit(IoC);
+	}
+
+	if (Last) {
+		SkI2cSndNAck(IoC);
+	}
+	else {
+		SkI2cSndAck(IoC);
+	}
+
+	return(Byte);
+}	/* SkI2cRcvByte */
+
+
+/*
+ * Start dialog and send device address
+ *
+ * Return 0 if acknowleged, 1 in case of an error
+ */
+int	SkI2cSndDev(
+SK_IOC	IoC,	/* I/O Context */
+int		Addr,	/* Device Address */
+int		Rw)		/* Read / Write Flag */
+{
+	SkI2cStart(IoC);
+	Rw = ~Rw;
+	Rw &= I2C_WRITE;
+	return(SkI2cSndByte(IoC, (Addr<<1) | Rw));
+}	/* SkI2cSndDev */
+
+#endif	/* SK_DIAG */
+
+/*----------------- I2C CTRL Register Functions ----------*/
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * returns	0:	success, transfer completes
+ *			1:	error,	 transfer does not complete, I2C transfer
+ *						 killed, wait loop terminated.
+ */
+int	SkI2cWait(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+int		Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */
+{
+	SK_U64	StartTime;
+	SK_U64	CurrentTime;
+	SK_U32	I2cCtrl;
+
+	StartTime = SkOsGetTime(pAC);
+
+	do {
+		CurrentTime = SkOsGetTime(pAC);
+
+		if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) {
+
+			SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG);
+#endif	/* !SK_DIAG */
+			return(1);
+		}
+
+		SK_I2C_GET_CTL(IoC, &I2cCtrl);
+
+#ifdef xYUKON_DBG
+		printf("StartTime=%lu, CurrentTime=%lu\n",
+			StartTime, CurrentTime);
+		if (kbhit()) {
+			return(1);
+		}
+#endif /* YUKON_DBG */
+
+	} while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31);
+
+	return(0);
+}	/* SkI2cWait */
+
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * Returns
+ *	Nothing
+ */
+void SkI2cWaitIrq(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	SK_SENSOR	*pSen;
+	SK_U64		StartTime;
+	SK_U32		IrqSrc;
+
+	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+
+	if (pSen->SenState == SK_SEN_IDLE) {
+		return;
+	}
+
+	StartTime = SkOsGetTime(pAC);
+	do {
+		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
+			SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG);
+#endif	/* !SK_DIAG */
+			return;
+		}
+		SK_IN32(IoC, B0_ISRC, &IrqSrc);
+	} while ((IrqSrc & IS_I2C_READY) == 0);
+
+	pSen->SenState = SK_SEN_IDLE;
+	return;
+}	/* SkI2cWaitIrq */
+
+/*
+ * writes a single byte or 4 bytes into the I2C device
+ *
+ * returns	0:	success
+ *			1:	error
+ */
+int SkI2cWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	I2cData,	/* I2C Data to write */
+int		I2cDev,		/* I2C Device Address */
+int		I2cReg,		/* I2C Device Register Address */
+int		I2cBurst)	/* I2C Burst Flag */
+{
+	SK_OUT32(IoC, B2_I2C_DATA, I2cData);
+	SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst);
+
+	return(SkI2cWait(pAC, IoC, I2C_WRITE));
+}	/* SkI2cWrite*/
+
+
+#ifdef	SK_DIAG
+
+/*
+ * reads a single byte or 4 bytes from the I2C device
+ *
+ * returns	the word read
+ */
+SK_U32 SkI2cRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		I2cDev,		/* I2C Device Address */
+int		I2cReg,		/* I2C Device Register Address */
+int		I2cBurst)	/* I2C Burst Flag */
+{
+	SK_U32	Data;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0);
+	SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst);
+
+	if (SkI2cWait(pAC, IoC, I2C_READ) != 0) {
+		w_print("%s\n", SKERR_I2C_E002MSG);
+	}
+
+	SK_IN32(IoC, B2_I2C_DATA, &Data);
+	return(Data);
+}	/* SkI2cRead */
+
+#endif	/* SK_DIAG */
+
+
+/*
+ * read a sensor's value
+ *
+ * This function reads a sensor's value from the I2C sensor chip. The sensor
+ * is defined by its index into the sensors database in the struct pAC points
+ * to.
+ * Returns
+ *		1 if the read is completed
+ *		0 if the read must be continued (I2C Bus still allocated)
+ */
+int	SkI2cReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+    if (pSen->SenRead != NULL) {
+	return((*pSen->SenRead)(pAC, IoC, pSen));
+    }
+    else
+	return(0); /* no success */
+}	/* SkI2cReadSensor*/
+
+/*
+ * Do the Init state 0 initialization
+ */
+static int SkI2cInit0(
+SK_AC	*pAC)	/* Adapter Context */
+{
+	int	i;
+
+	/* Begin with first sensor */
+	pAC->I2c.CurrSens = 0;
+
+	/* Begin with timeout control for state machine */
+	pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE;
+
+	/* Set sensor number to zero */
+	pAC->I2c.MaxSens = 0;
+
+#ifndef	SK_DIAG
+	/* Initialize Number of Dummy Reads */
+	pAC->I2c.DummyReads = SK_MAX_SENSORS;
+#endif
+
+	for (i = 0; i < SK_MAX_SENSORS; i++) {
+		pAC->I2c.SenTable[i].SenDesc = "unknown";
+		pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN;
+		pAC->I2c.SenTable[i].SenThreErrHigh = 0;
+		pAC->I2c.SenTable[i].SenThreErrLow = 0;
+		pAC->I2c.SenTable[i].SenThreWarnHigh = 0;
+		pAC->I2c.SenTable[i].SenThreWarnLow = 0;
+		pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+		pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE;
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = NULL;
+		pAC->I2c.SenTable[i].SenDev = 0;
+	}
+
+	/* Now we are "INIT data"ed */
+	pAC->I2c.InitLevel = SK_INIT_DATA;
+	return(0);
+}	/* SkI2cInit0*/
+
+
+/*
+ * Do the init state 1 initialization
+ *
+ * initialize the following register of the LM80:
+ * Configuration register:
+ * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT
+ *
+ * Interrupt Mask Register 1:
+ * - all interrupts are Disabled (0xff)
+ *
+ * Interrupt Mask Register 2:
+ * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter.
+ *
+ * Fan Divisor/RST_OUT register:
+ * - Divisors set to 1 (bits 00), all others 0s.
+ *
+ * OS# Configuration/Temperature resolution Register:
+ * - all 0s
+ *
+ */
+static int SkI2cInit1(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+    int i;
+    SK_U8 I2cSwCtrl;
+	SK_GEPORT *pPrt;	/* GIni Port struct pointer */
+
+	if (pAC->I2c.InitLevel != SK_INIT_DATA) {
+		/* ReInit not needed in I2C module */
+		return(0);
+	}
+
+    /* Set the Direction of I2C-Data Pin to IN */
+    SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA);
+    /* Check for 32-Bit Yukon with Low at I2C-Data Pin */
+	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+	if ((I2cSwCtrl & I2C_DATA) == 0) {
+		/* this is a 32-Bit board */
+		pAC->GIni.GIYukon32Bit = SK_TRUE;
+	return(0);
+    }
+
+	/* Check for 64 Bit Yukon without sensors */
+	if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_CFG, 0) != 0) {
+	return(0);
+    }
+
+	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_1, 0);
+
+	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_2, 0);
+
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_FAN_CTRL, 0);
+
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_TEMP_CTRL, 0);
+
+	(void)SkI2cWrite(pAC, IoC, LM80_CFG_START, LM80_ADDR, LM80_CFG, 0);
+
+	/*
+	 * MaxSens has to be updated here, because PhyType is not
+	 * set when performing Init Level 0
+	 */
+    pAC->I2c.MaxSens = 5;
+
+	pPrt = &pAC->GIni.GP[0];
+
+	if (pAC->GIni.GIGenesis) {
+		if (pPrt->PhyType == SK_PHY_BCOM) {
+			if (pAC->GIni.GIMacsFound == 1) {
+				pAC->I2c.MaxSens += 1;
+			}
+			else {
+				pAC->I2c.MaxSens += 3;
+			}
+		}
+	}
+	else {
+		pAC->I2c.MaxSens += 3;
+	}
+
+	for (i = 0; i < pAC->I2c.MaxSens; i++) {
+		switch (i) {
+		case 0:
+			pAC->I2c.SenTable[i].SenDesc = "Temperature";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+			break;
+		case 1:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+			break;
+		case 2:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO;
+			break;
+		case 3:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+			break;
+		case 4:
+			if (pAC->GIni.GIGenesis) {
+				if (pPrt->PhyType == SK_PHY_BCOM) {
+					pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL";
+					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+				}
+				else {
+					pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+				}
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN;
+				if (pAC->GIni.GIVauxAvail) {
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+				}
+				else {
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR;
+				}
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+			break;
+		case 5:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC-Co 1V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR;
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+			break;
+		case 6:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3";
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+			break;
+		case 7:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN;
+			}
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+				SKERR_I2C_E001, SKERR_I2C_E001MSG);
+			break;
+		}
+
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+		pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+	}
+
+#ifndef	SK_DIAG
+	pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+#endif	/* !SK_DIAG */
+
+	/* Clear I2C IRQ */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+	/* Now we are I/O initialized */
+	pAC->I2c.InitLevel = SK_INIT_IO;
+	return(0);
+}	/* SkI2cInit1 */
+
+
+/*
+ * Init level 2: Start first sensor read.
+ */
+static int SkI2cInit2(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	int		ReadComplete;
+	SK_SENSOR	*pSen;
+
+	if (pAC->I2c.InitLevel != SK_INIT_IO) {
+		/* ReInit not needed in I2C module */
+		/* Init0 and Init2 not permitted */
+		return(0);
+	}
+
+	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+	ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+	if (ReadComplete) {
+		SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG);
+	}
+
+	/* Now we are correctly initialized */
+	pAC->I2c.InitLevel = SK_INIT_RUN;
+
+	return(0);
+}	/* SkI2cInit2*/
+
+
+/*
+ * Initialize I2C devices
+ *
+ * Get the first voltage value and discard it.
+ * Go into temperature read mode. A default pointer is not set.
+ *
+ * The things to be done depend on the init level in the parameter list:
+ * Level 0:
+ *	Initialize only the data structures. Do NOT access hardware.
+ * Level 1:
+ *	Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts.
+ * Level 2:
+ *	Everything is possible. Interrupts may be used from now on.
+ *
+ * return:
+ *	0 = success
+ *	other = error.
+ */
+int	SkI2cInit(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context needed in levels 1 and 2 */
+int		Level)	/* Init Level */
+{
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		return(SkI2cInit0(pAC));
+	case SK_INIT_IO:
+		return(SkI2cInit1(pAC, IoC));
+	case SK_INIT_RUN:
+		return(SkI2cInit2(pAC, IoC));
+	default:
+		break;
+	}
+
+	return(0);
+}	/* SkI2cInit */
+
+
+#ifndef SK_DIAG
+
+/*
+ * Interrupt service function for the I2C Interface
+ *
+ * Clears the Interrupt source
+ *
+ * Reads the register and check it for sending a trap.
+ *
+ * Starts the timer if necessary.
+ */
+void SkI2cIsr(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	SK_EVPARA	Para;
+
+	/* Clear I2C IRQ */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+	Para.Para64 = 0;
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para);
+}	/* SkI2cIsr */
+
+
+/*
+ * Check this sensors Value against the threshold and send events.
+ */
+static void SkI2cCheckSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_SENSOR	*pSen)
+{
+	SK_EVPARA	ParaLocal;
+	SK_BOOL		TooHigh;	/* Is sensor too high? */
+	SK_BOOL		TooLow;		/* Is sensor too low? */
+	SK_U64		CurrTime;	/* Current Time */
+	SK_BOOL		DoTrapSend;	/* We need to send a trap */
+	SK_BOOL		DoErrLog;	/* We need to log the error */
+	SK_BOOL		IsError;	/* We need to log the error */
+
+	/* Check Dummy Reads first */
+	if (pAC->I2c.DummyReads > 0) {
+		pAC->I2c.DummyReads--;
+		return;
+	}
+
+	/* Get the current time */
+	CurrTime = SkOsGetTime(pAC);
+
+	/* Set para to the most useful setting: The current sensor. */
+	ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens;
+
+	/* Check the Value against the thresholds. First: Error Thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
+	TooLow = (pSen->SenValue < pSen->SenThreErrLow);
+
+	IsError = SK_FALSE;
+	if (TooHigh || TooLow) {
+		/* Error condition is satisfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		/* Now error condition is satisfied */
+		IsError = SK_TRUE;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_ERR) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
+			pSen->SenBegErrTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_ERR;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastErrTrapTS = CurrTime;
+			pSen->SenErrCts++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_ERR_UPP :
+				SK_PNMI_EVT_SEN_ERR_LOW),
+				ParaLocal);
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastErrLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011,
+					SKERR_I2C_E011MSG);
+			} else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012,
+					SKERR_I2C_E012MSG);
+			} else
+			{
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015,
+					SKERR_I2C_E015MSG);
+			}
+		}
+	}
+
+	/* Check the Value against the thresholds */
+	/* 2nd: Warning thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh);
+	TooLow = (pSen->SenValue < pSen->SenThreWarnLow);
+
+	if (!IsError && (TooHigh || TooLow)) {
+		/* Error condition is satisfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_WARN) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
+			pSen->SenBegWarnTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_WARN;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastWarnTrapTS = CurrTime;
+			pSen->SenWarnCts++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_WAR_UPP :
+				SK_PNMI_EVT_SEN_WAR_LOW),
+				ParaLocal);
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastWarnLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009,
+					SKERR_I2C_E009MSG);
+			} else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010,
+					SKERR_I2C_E010MSG);
+			} else
+			{
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014,
+					SKERR_I2C_E014MSG);
+			}
+		}
+	}
+
+	/* Check for NO error at all */
+	if (!IsError && !TooHigh && !TooLow) {
+		/* Set o.k. Status if no error and no warning condition */
+		pSen->SenErrFlag = SK_SEN_ERR_OK;
+	}
+
+	/* End of check against the thresholds */
+
+	/* Bug fix AF: 16.Aug.2001: Correct the init base
+	 * of LM80 sensor.
+	 */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) {
+
+	pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) {
+			/* 5V PCI-IO Voltage */
+			pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR;
+		}
+		else {
+			/* 3.3V PCI-IO Voltage */
+			pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN;
+			pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR;
+		}
+	}
+
+#if 0
+    /* Dynamic thresholds also for VAUX of LM80 sensor */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) {
+
+	pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		/* 3.3V VAUX Voltage */
+		if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) {
+			pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+		}
+		/* 0V VAUX Voltage */
+		else {
+			pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR;
+			pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR;
+		}
+	}
+
+	/*
+	 * Check initialization state:
+	 * The VIO Thresholds need adaption
+	 */
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2C &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2) {
+		pSen->SenThreErrLow = SK_SEN_ERRLOW2C;
+		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C;
+		pSen->SenInit = SK_TRUE;
+	}
+
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2 &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2C) {
+		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C;
+		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C;
+		pSen->SenInit = SK_TRUE;
+	}
+#endif
+
+	if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) {
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
+	}
+}	/* SkI2cCheckSensor*/
+
+
+/*
+ * The only Event to be served is the timeout event
+ *
+ */
+int	SkI2cEvent(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Module specific Event */
+SK_EVPARA	Para)	/* Event specific Parameter */
+{
+	int			ReadComplete;
+	SK_SENSOR	*pSen;
+	SK_U32		Time;
+	SK_EVPARA	ParaLocal;
+	int			i;
+
+	/* New case: no sensors */
+	if (pAC->I2c.MaxSens == 0) {
+		return(0);
+	}
+
+	switch (Event) {
+	case SK_I2CEV_IRQ:
+		pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+		ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+		if (ReadComplete) {
+			/* Check sensor against defined thresholds */
+			SkI2cCheckSensor (pAC, pSen);
+
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
+			if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+	else {
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE;
+
+	    SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+		break;
+	case SK_I2CEV_TIM:
+		if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) {
+
+			ParaLocal.Para64 = (SK_U64)0;
+			SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer);
+
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+			if (ReadComplete) {
+				/* Check sensor against defined thresholds */
+				SkI2cCheckSensor (pAC, pSen);
+
+				/* Increment Current sensor and set appropriate Timeout */
+				pAC->I2c.CurrSens++;
+				if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+					pAC->I2c.CurrSens = 0;
+					Time = SK_I2C_TIM_LONG;
+				}
+				else {
+					Time = SK_I2C_TIM_SHORT;
+				}
+
+				/* Start Timer */
+				ParaLocal.Para64 = (SK_U64)0;
+
+				pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+				SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+					SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+			}
+		}
+		else {
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			pSen->SenErrFlag = SK_SEN_ERR_FAULTY;
+			SK_I2C_STOP(IoC);
+
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
+			if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+		break;
+	case SK_I2CEV_CLEAR:
+		for (i = 0; i < SK_MAX_SENSORS; i++) {
+			pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+			pAC->I2c.SenTable[i].SenErrCts = 0;
+			pAC->I2c.SenTable[i].SenWarnCts = 0;
+			pAC->I2c.SenTable[i].SenBegErrTS = 0;
+			pAC->I2c.SenTable[i].SenBegWarnTS = 0;
+			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG);
+	}
+
+	return(0);
+}	/* SkI2cEvent*/
+
+#endif	/* !SK_DIAG */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c
new file mode 100644
index 0000000..687572b
--- /dev/null
+++ b/drivers/net/sk98lin/sklm80.c
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * Name:	sklm80.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.20 $
+ * Date:	$Date: 2002/08/13 09:16:27 $
+ * Purpose:	Funktions to access Voltage and Temperature Sensor (LM80)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sklm80.c,v $
+ *	Revision 1.20  2002/08/13 09:16:27  rschmidt
+ *	Changed return value for SkLm80ReadSensor() back to 'int'
+ *	Editorial changes
+ *
+ *	Revision 1.19  2002/08/06 09:43:31  jschmalz
+ *	Extensions and changes for Yukon
+ *
+ *	Revision 1.18  2002/08/02 12:26:57  rschmidt
+ *	Editorial changes
+ *
+ *	Revision 1.17  1999/11/22 13:35:51  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.16  1999/05/27 14:05:47  malthoff
+ *	Fans: Set SenVal to 0 if the fan value is 0 or 0xff. Both values
+ *	are outside the limits (0: div zero error, 0xff: value not in
+ *	range, assume 0).
+ *
+ *	Revision 1.15  1999/05/27 13:38:51  malthoff
+ *	Pervent from Division by zero errors.
+ *
+ *	Revision 1.14  1999/05/20 09:20:01  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *
+ *	Revision 1.13  1998/10/22 09:48:14  gklug
+ *	fix: SysKonnectFileId typo
+ *
+ *	Revision 1.12  1998/10/09 06:12:06  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *
+ *	Revision 1.11  1998/09/04 08:33:48  malthoff
+ *	bug fix: SenState = SK_SEN_IDLE when
+ *	leaving SK_SEN_VALEXT state
+ *
+ *	Revision 1.10  1998/08/20 12:02:10  gklug
+ *	fix: compiler warnings type mismatch
+ *
+ *	Revision 1.9  1998/08/20 11:37:38  gklug
+ *	chg: change Ioc to IoC
+ *
+ *	Revision 1.8  1998/08/19 12:20:58  gklug
+ *	fix: remove struct from C files (see CCC)
+ *
+ *	Revision 1.7  1998/08/17 07:04:57  malthoff
+ *	Take SkLm80RcvReg() function from ski2c.c.
+ *	Add IoC parameter to BREAK_OR_WAIT() macro.
+ *
+ *	Revision 1.6  1998/08/14 07:11:28  malthoff
+ *	remove pAc with pAC.
+ *
+ *	Revision 1.5  1998/08/14 06:46:55  gklug
+ *	fix: temperature can get negative
+ *
+ *	Revision 1.4  1998/08/13 08:27:04  gklug
+ *	add: temperature reading now o.k.
+ *	fix: pSen declaration, SK_ERR_LOG call, ADDR macro
+ *
+ *	Revision 1.3  1998/08/13 07:28:21  gklug
+ *	fix: pSen was wrong initialized
+ *	add: correct conversion for voltage readings
+ *
+ *	Revision 1.2  1998/08/11 07:52:14  gklug
+ *	add: Lm80 read sensor function
+ *
+ *	Revision 1.1  1998/07/17 09:57:12  gklug
+ *	initial version
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+	LM80 functions
+*/
+static const char SysKonnectFileId[] =
+	"$Id: sklm80.c,v 1.20 2002/08/13 09:16:27 rschmidt Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef	SK_DIAG
+#define	BREAK_OR_WAIT(pAC,IoC,Event)	SkI2cWait(pAC,IoC,Event)
+#else	/* nSK_DIAG */
+#define	BREAK_OR_WAIT(pAC,IoC,Event)	break
+#endif	/* nSK_DIAG */
+
+#ifdef	SK_DIAG
+/*
+ * read the register 'Reg' from the device 'Dev'
+ *
+ * return 	read error	-1
+ *		success		the read value
+ */
+int	SkLm80RcvReg(
+SK_IOC	IoC,		/* Adapter Context */
+int		Dev,		/* I2C device address */
+int		Reg)		/* register to read */
+{
+	int	Val = 0;
+	int	TempExt;
+
+	/* Signal device number */
+	if (SkI2cSndDev(IoC, Dev, I2C_WRITE)) {
+		return(-1);
+	}
+
+	if (SkI2cSndByte(IoC, Reg)) {
+		return(-1);
+	}
+
+	/* repeat start */
+	if (SkI2cSndDev(IoC, Dev, I2C_READ)) {
+		return(-1);
+	}
+
+	switch (Reg) {
+	case LM80_TEMP_IN:
+		Val = (int)SkI2cRcvByte(IoC, 1);
+
+		/* First: correct the value: it might be negative */
+		if ((Val & 0x80) != 0) {
+			/* Value is negative */
+			Val = Val - 256;
+		}
+		Val = Val * SK_LM80_TEMP_LSB;
+		SkI2cStop(IoC);
+
+		TempExt = (int)SkLm80RcvReg(IoC, LM80_ADDR, LM80_TEMP_CTRL);
+
+		if (Val > 0) {
+			Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		else {
+			Val -= ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		return(Val);
+		break;
+	case LM80_VT0_IN:
+	case LM80_VT1_IN:
+	case LM80_VT2_IN:
+	case LM80_VT3_IN:
+		Val = (int)SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
+		break;
+
+	default:
+		Val = (int)SkI2cRcvByte(IoC, 1);
+		break;
+	}
+
+	SkI2cStop(IoC);
+	return(Val);
+}
+#endif	/* SK_DIAG */
+
+/*
+ * read a sensors value (LM80 specific)
+ *
+ * This function reads a sensors value from the I2C sensor chip LM80.
+ * The sensor is defined by its index into the sensors database in the struct
+ * pAC points to.
+ *
+ * Returns	1 if the read is completed
+ *		0 if the read must be continued (I2C Bus still allocated)
+ */
+int SkLm80ReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context needed in level 1 and 2 */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+	SK_I32		Value;
+
+	switch (pSen->SenState) {
+	case SK_SEN_IDLE:
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, pSen->SenReg, 0);
+
+		pSen->SenState = SK_SEN_VALUE ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+
+	case SK_SEN_VALUE:
+		/* Read value from data register */
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+
+		Value &= 0xff; /* only least significant byte is valid */
+
+		/* Do NOT check the Value against the thresholds */
+		/* Checking is done in the calling instance */
+
+		if (pSen->SenType == SK_SEN_VOLT) {
+			/* Voltage sensor */
+			pSen->SenValue = Value * SK_LM80_VT_LSB;
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		if (pSen->SenType == SK_SEN_FAN) {
+			if (Value != 0 && Value != 0xff) {
+				/* Fan speed counter */
+				pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
+			}
+			else {
+				/* Indicate Fan error */
+				pSen->SenValue = 0;
+			}
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		/* First: correct the value: it might be negative */
+		if ((Value & 0x80) != 0) {
+			/* Value is negative */
+			Value = Value - 256;
+		}
+
+		/* We have a temperature sensor and need to get the signed extension.
+		 * For now we get the extension from the last reading, so in the normal
+		 * case we won't see flickering temperatures.
+		 */
+		pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
+			(pSen->SenValue % SK_LM80_TEMP_LSB);
+
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, LM80_TEMP_CTRL, 0);
+
+		pSen->SenState = SK_SEN_VALEXT ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+
+	case SK_SEN_VALEXT:
+		/* Read value from data register */
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+		Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
+
+		/* cut the LSB bit */
+		pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
+			SK_LM80_TEMP_LSB);
+
+		if (pSen->SenValue < 0) {
+			/* Value negative: The bit value must be subtracted */
+			pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		else {
+			/* Value positive: The bit value must be added */
+			pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+
+		pSen->SenState = SK_SEN_IDLE ;
+		return(1);
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
+		return(1);
+	}
+
+	/* Not completed */
+	return(0);
+}
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skproc.c b/drivers/net/sk98lin/skproc.c
new file mode 100644
index 0000000..4e34073
--- /dev/null
+++ b/drivers/net/sk98lin/skproc.c
@@ -0,0 +1,515 @@
+/******************************************************************************
+ *
+ * Name:    skproc.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:    $Date: 2003/02/25 14:16:37 $
+ * Purpose:	Funktions to display statictic data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	Created 22-Nov-2000
+ *	Author: Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skproc.c,v $
+ *	Revision 1.4  2003/02/25 14:16:37  mlindner
+ *	Fix: Copyright statement
+ *
+ *	Revision 1.3  2002/10/02 12:59:51  mlindner
+ *	Add: Support for Yukon
+ *	Add: Speed check and setup
+ *	Add: Merge source for kernel 2.2.x and 2.4.x
+ *	Add: Read sensor names directly from VPD
+ *	Fix: Volt values
+ *
+ *	Revision 1.2.2.7  2002/01/14 12:45:15  mlindner
+ *	Fix: Editorial changes
+ *
+ *	Revision 1.2.2.6  2001/12/06 15:26:07  mlindner
+ *	Fix: Return value of proc_read
+ *
+ *	Revision 1.2.2.5  2001/12/06 09:57:39  mlindner
+ *	New ProcFs entries
+ *
+ *	Revision 1.2.2.4  2001/09/05 12:16:02  mlindner
+ *	Add: New ProcFs entries
+ *	Fix: Counter Errors (Jumbo == to long errors)
+ *	Fix: Kernel error compilation
+ *	Fix: too short counters
+ *
+ *	Revision 1.2.2.3  2001/06/25 07:26:26  mlindner
+ *	Add: More error messages
+ *
+ *	Revision 1.2.2.2  2001/03/15 12:50:13  mlindner
+ *	fix: ProcFS owner protection
+ *
+ *	Revision 1.2.2.1  2001/03/12 16:43:48  mlindner
+ *	chg: 2.4 requirements for procfs
+ *
+ *	Revision 1.1  2001/01/22 14:15:31  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#include <linux/proc_fs.h>
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#define ZEROPAD		1		/* pad with zero */
+#define SIGN		2		/* unsigned/signed long */
+#define PLUS		4		/* show plus */
+#define SPACE		8		/* space if plus */
+#define LEFT		16		/* left justified */
+#define SPECIALX	32		/* 0x */
+#define LARGE		64
+
+extern SK_AC				*pACList;
+extern struct net_device 	*SkGeRootDev;
+
+extern char * SkNumber(
+	char * str,
+	long long num,
+	int base,
+	int size,
+	int precision,
+	int type);
+
+
+/*****************************************************************************
+ *
+ * 	proc_read - print "summaries" entry
+ *
+ * Description:
+ *  This function fills the proc entry with statistic data about
+ *  the ethernet device.
+ *
+ *
+ * Returns: buffer with statistic data
+ *
+ */
+int proc_read(char *buffer,
+char **buffer_location,
+off_t offset,
+int buffer_length,
+int *eof,
+void *data)
+{
+	int len = 0;
+	int t;
+	int i;
+	DEV_NET					*pNet;
+	SK_AC					*pAC;
+	char 					test_buf[100];
+	char					sens_msg[50];
+	unsigned long			Flags;
+	unsigned int			Size;
+	struct SK_NET_DEVICE 		*next;
+	struct SK_NET_DEVICE 		*SkgeProcDev = SkGeRootDev;
+
+	SK_PNMI_STRUCT_DATA 	*pPnmiStruct;
+	SK_PNMI_STAT		*pPnmiStat;
+	struct proc_dir_entry *file = (struct proc_dir_entry*) data;
+
+	while (SkgeProcDev) {
+		pNet = (DEV_NET*) SkgeProcDev->priv;
+		pAC = pNet->pAC;
+		next = pAC->Next;
+		pPnmiStruct = &pAC->PnmiStruct;
+		/* NetIndex in GetStruct is now required, zero is only dummy */
+
+		for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
+			if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
+				t--;
+
+			spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+			Size = SK_PNMI_STRUCT_SIZE;
+			SkPnmiGetStruct(pAC, pAC->IoBase,
+				pPnmiStruct, &Size, t-1);
+			spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+			if (strcmp(pAC->dev[t-1]->name, file->name) == 0) {
+				pPnmiStat = &pPnmiStruct->Stat[0];
+				len = sprintf(buffer,
+					"\nDetailed statistic for device %s\n",
+					pAC->dev[t-1]->name);
+				len += sprintf(buffer + len,
+					"=======================================\n");
+
+				/* Board statistics */
+				len += sprintf(buffer + len,
+					"\nBoard statistics\n\n");
+				len += sprintf(buffer + len,
+					"Active Port                    %c\n",
+					'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
+					Net[t-1].PrefPort]->PortNumber);
+				len += sprintf(buffer + len,
+					"Preferred Port                 %c\n",
+					'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
+					Net[t-1].PrefPort]->PortNumber);
+
+				len += sprintf(buffer + len,
+					"Bus speed (MHz)                %d\n",
+					pPnmiStruct->BusSpeed);
+
+				len += sprintf(buffer + len,
+					"Bus width (Bit)                %d\n",
+					pPnmiStruct->BusWidth);
+				len += sprintf(buffer + len,
+					"Hardware revision              v%d.%d\n",
+					(pAC->GIni.GIPciHwRev >> 4) & 0x0F,
+					pAC->GIni.GIPciHwRev & 0x0F);
+
+				/* Print sensor informations */
+				for (i=0; i < pAC->I2c.MaxSens; i ++) {
+					/* Check type */
+					switch (pAC->I2c.SenTable[i].SenType) {
+					case 1:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (C)");
+						len += sprintf(buffer + len,
+							"%-25s      %d.%02d\n",
+							sens_msg,
+							pAC->I2c.SenTable[i].SenValue / 10,
+							pAC->I2c.SenTable[i].SenValue % 10);
+
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (F)");
+						len += sprintf(buffer + len,
+							"%-25s      %d.%02d\n",
+							sens_msg,
+							((((pAC->I2c.SenTable[i].SenValue)
+							*10)*9)/5 + 3200)/100,
+							((((pAC->I2c.SenTable[i].SenValue)
+							*10)*9)/5 + 3200) % 10);
+						break;
+					case 2:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (V)");
+						len += sprintf(buffer + len,
+							"%-25s      %d.%03d\n",
+							sens_msg,
+							pAC->I2c.SenTable[i].SenValue / 1000,
+							pAC->I2c.SenTable[i].SenValue % 1000);
+						break;
+					case 3:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (rpm)");
+						len += sprintf(buffer + len,
+							"%-25s      %d\n",
+							sens_msg,
+							pAC->I2c.SenTable[i].SenValue);
+						break;
+					default:
+						break;
+					}
+				}
+
+				/*Receive statistics */
+				len += sprintf(buffer + len,
+				"\nReceive statistics\n\n");
+
+				len += sprintf(buffer + len,
+					"Received bytes                 %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received packets               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxOkCts,
+					10,0,-1,0));
+#if 0
+				if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC &&
+					pAC->HWRevision < 12) {
+					pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
+						pPnmiStat->StatRxShortsCts;
+					pPnmiStat->StatRxShortsCts = 0;
+				}
+#endif
+				if (pNet->Mtu > 1500)
+					pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
+						pPnmiStat->StatRxTooLongCts;
+
+				len += sprintf(buffer + len,
+					"Receive errors                 %s\n",
+					SkNumber(test_buf, pPnmiStruct->InErrorsCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Receive drops                  %s\n",
+					SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received multicast             %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Receive error types\n");
+				len += sprintf(buffer + len,
+					"   length                      %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   buffer overflow             %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   bad crc                     %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   framing                     %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFramingCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   missed frames               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
+					10, 0, -1, 0));
+
+				if (pNet->Mtu > 1500)
+					pPnmiStat->StatRxTooLongCts = 0;
+
+				len += sprintf(buffer + len,
+					"   too long                    %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxTooLongCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   carrier extension           %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxCextCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   too short                   %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxShortsCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   symbol                      %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxSymbolCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   LLC MAC size                %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxIRLengthCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   carrier event               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxCarrierCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   jabber                      %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxJabberCts,
+					10, 0, -1, 0));
+
+
+				/*Transmit statistics */
+				len += sprintf(buffer + len,
+				"\nTransmit statistics\n\n");
+
+				len += sprintf(buffer + len,
+					"Transmited bytes               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmited packets             %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit errors                %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit dropped               %s\n",
+					SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit collisions            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit errors types\n");
+				len += sprintf(buffer + len,
+					"   excessive collision         %ld\n",
+					pAC->stats.tx_aborted_errors);
+				len += sprintf(buffer + len,
+					"   carrier                     %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   fifo underrun               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   heartbeat                   %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   window                      %ld\n",
+					pAC->stats.tx_window_errors);
+
+			}
+		}
+		SkgeProcDev = next;
+	}
+	if (offset >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*buffer_location = buffer + offset;
+	if (buffer_length >= len - offset) {
+		*eof = 1;
+	}
+	return (min_t(int, buffer_length, len - offset));
+}
+
+
+/*****************************************************************************
+ *
+ * SkDoDiv - convert 64bit number
+ *
+ * Description:
+ *	This function "converts" a long long number.
+ *
+ * Returns:
+ *	remainder of division
+ */
+static long SkDoDiv (long long Dividend, int Divisor, long long *pErg)
+{
+ long   	Rest;
+ long long 	Ergebnis;
+ long   	Akku;
+
+
+ Akku  = Dividend >> 32;
+
+ Ergebnis = ((long long) (Akku / Divisor)) << 32;
+ Rest = Akku % Divisor ;
+
+ Akku = Rest << 16;
+ Akku |= ((Dividend & 0xFFFF0000) >> 16);
+
+
+ Ergebnis += ((long long) (Akku / Divisor)) << 16;
+ Rest = Akku % Divisor ;
+
+ Akku = Rest << 16;
+ Akku |= (Dividend & 0xFFFF);
+
+ Ergebnis += (Akku / Divisor);
+ Rest = Akku % Divisor ;
+
+ *pErg = Ergebnis;
+ return (Rest);
+}
+
+
+#if 0
+#define do_div(n,base) ({ \
+long long __res; \
+__res = ((unsigned long long) n) % (unsigned) base; \
+n = ((unsigned long long) n) / (unsigned) base; \
+__res; })
+
+#endif
+
+
+/*****************************************************************************
+ *
+ * SkNumber - Print results
+ *
+ * Description:
+ *	This function converts a long long number into a string.
+ *
+ * Returns:
+ *	number as string
+ */
+char * SkNumber(char * str, long long num, int base, int size, int precision
+	,int type)
+{
+	char c,sign,tmp[66], *strorg = str;
+	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	int i;
+
+	if (type & LARGE)
+		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if (num < 0) {
+			sign = '-';
+			num = -num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIALX) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[SkDoDiv(num,base, &num)];
+
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT)))
+		while(size-->0)
+			*str++ = ' ';
+	if (sign)
+		*str++ = sign;
+	if (type & SPECIALX) {
+		if (base==8)
+			*str++ = '0';
+		else if (base==16) {
+			*str++ = '0';
+			*str++ = digits[33];
+		}
+	}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			*str++ = c;
+	while (i < precision--)
+		*str++ = '0';
+	while (i-- > 0)
+		*str++ = tmp[i];
+	while (size-- > 0)
+		*str++ = ' ';
+
+	str[0] = '\0';
+
+	return strorg;
+}
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c
new file mode 100644
index 0000000..c49baed
--- /dev/null
+++ b/drivers/net/sk98lin/skqueue.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.18 $
+ * Date:	$Date: 2002/05/07 14:11:11 $
+ * Purpose:	Management of an event queue.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skqueue.c,v $
+ *	Revision 1.18  2002/05/07 14:11:11  rwahl
+ *	Fixed Watcom Precompiler error.
+ *
+ *	Revision 1.17  2002/03/25 10:06:41  mkunz
+ *	SkIgnoreEvent deleted
+ *
+ *	Revision 1.16  2002/03/15 10:51:59  mkunz
+ *	Added event classes for link aggregation
+ *
+ *	Revision 1.15  1999/11/22 13:36:29  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.14  1998/10/15 15:11:35  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *
+ *	Revision 1.13  1998/09/08 08:47:52  gklug
+ *	add: init level handling
+ *
+ *	Revision 1.12  1998/09/08 07:43:20  gklug
+ *	fix: Sirq Event function name
+ *
+ *	Revision 1.11  1998/09/08 05:54:34  gklug
+ *	chg: define SK_CSUM is replaced by SK_USE_CSUM
+ *
+ *	Revision 1.10  1998/09/03 14:14:49  gklug
+ *	add: CSUM and HWAC Eventclass and function.
+ *
+ *	Revision 1.9  1998/08/19 09:50:50  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.8  1998/08/17 13:43:11  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *
+ *	Revision 1.7  1998/08/14 07:09:11  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.6  1998/08/11 12:13:14  gklug
+ *	add: return code feature of Event service routines
+ *	add: correct Error log calls
+ *
+ *	Revision 1.5  1998/08/07 12:53:45  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.4  1998/08/07 09:20:48  gklug
+ *	adapt functions to C coding conventions.
+ *
+ *	Revision 1.3  1998/08/05 11:29:32  gklug
+ *	rmv: Timer event entry. Timer will queue event directly
+ *
+ *	Revision 1.2  1998/07/31 11:22:40  gklug
+ *	Initial version
+ *
+ *	Revision 1.1  1998/07/30 15:14:01  gklug
+ *	Initial version. Adapted from SMT
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.18 2002/05/07 14:11:11 rwahl Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skqueue.h"		/* Queue Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ *
+ * Must be called during init level 0.
+ */
+void	SkEventInit(
+SK_AC	*pAC,	/* Adapter context */
+SK_IOC	Ioc,	/* IO context */
+int	Level)	/* Init level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue ;
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * add event to queue
+ */
+void	SkEventQueue(
+SK_AC		*pAC,	/* Adapters context */
+SK_U32		Class,	/* Event Class */
+SK_U32		Event,	/* Event to be queued */
+SK_EVPARA	Para)	/* Event parameter */
+{
+	pAC->Event.EvPut->Class = Class ;
+	pAC->Event.EvPut->Event = Event ;
+	pAC->Event.EvPut->Para = Para ;
+	if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT])
+		pAC->Event.EvPut = pAC->Event.EvQueue ;
+
+	if (pAC->Event.EvPut == pAC->Event.EvGet) {
+		SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG) ;
+	}
+}
+
+/*
+ * event dispatcher
+ *	while event queue is not empty
+ *		get event from queue
+ *		send command to state machine
+ *	end
+ *	return error reported by individual Event function
+ *		0 if no error occured.
+ */
+int	SkEventDispatcher(
+SK_AC	*pAC,	/* Adapters Context */
+SK_IOC	Ioc)	/* Io context */
+{
+	SK_EVENTELEM	*pEv ;	/* pointer into queue */
+	SK_U32			Class ;
+	int			Rtv ;
+
+	pEv = pAC->Event.EvGet ;
+	PRINTF("dispatch get %x put %x\n",pEv,pAC->Event.ev_put) ;
+	while (pEv != pAC->Event.EvPut) {
+		PRINTF("dispatch Class %d Event %d\n",pEv->Class,pEv->Event) ;
+		switch(Class = pEv->Class) {
+#ifndef SK_USE_LAC_EV
+		case SKGE_RLMT :	/* RLMT Event */
+			Rtv = SkRlmtEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_I2C :		/* I2C Event */
+			Rtv = SkI2cEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_PNMI :
+			Rtv = SkPnmiEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif /* SK_USE_LAC_EV */
+		case SKGE_DRV :		/* Driver Event */
+			Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#ifndef SK_USE_SW_TIMER
+		case SKGE_HWAC :
+			Rtv = SkGeSirqEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#else /* !SK_USE_SW_TIMER */
+	case SKGE_SWT :
+			Rtv = SkSwtEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif /* !SK_USE_SW_TIMER */
+#ifdef SK_USE_LAC_EV
+		case SKGE_LACP :
+			Rtv = SkLacpEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_RSF :
+			Rtv = SkRsfEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_MARKER :
+			Rtv = SkMarkerEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_FD :
+			Rtv = SkFdEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif /* SK_USE_LAC_EV */
+#ifdef	SK_USE_CSUM
+		case SKGE_CSUM :
+			Rtv = SkCsEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif	/* SK_USE_CSUM */
+		default :
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002,
+				SKERR_Q_E002MSG) ;
+			Rtv = 0;
+		}
+
+		if (Rtv != 0) {
+			return(Rtv) ;
+		}
+
+		if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT])
+			pEv = pAC->Event.EvQueue ;
+
+		/* Renew get: it is used in queue_events to detect overruns */
+		pAC->Event.EvGet = pEv;
+	}
+
+	return(0) ;
+}
+
+#endif /* CONFIG_SK98 */
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c
new file mode 100644
index 0000000..f8a3b41
--- /dev/null
+++ b/drivers/net/sk98lin/skrlmt.c
@@ -0,0 +1,3508 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.68 $
+ * Date:	$Date: 2003/01/31 15:26:56 $
+ * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skrlmt.c,v $
+ *	Revision 1.68  2003/01/31 15:26:56  rschmidt
+ *	Added init for local variables in RlmtInit().
+ *
+ *	Revision 1.67  2003/01/31 14:12:41  mkunz
+ *	single port adapter runs now with two identical MAC addresses
+ *
+ *	Revision 1.66  2002/09/23 15:14:19  rwahl
+ *	- Reset broadcast timestamp on link down.
+ *	- Editorial corrections.
+ *
+ *	Revision 1.65  2002/07/22 14:29:48  rwahl
+ *	- Removed BRK statement from debug check.
+ *
+ *	Revision 1.64  2001/11/28 19:36:14  rwahl
+ *	- RLMT Packets sent to an invalid MAC address in CLP/CLPSS mode
+ *	  (#10650).
+ *	- Reworked fix for port switching in CLS mode (#10639)
+ *	 (no dependency to RLMT module).
+ *	- Enabled dbg output for entry/exit of event functions.
+ *	- Editorial changes.
+ *
+ *	Revision 1.63  2001/10/26 07:53:18  afischer
+ *	Port switching bug in `check local link` mode
+ *
+ *	Revision 1.62  2001/07/03 12:16:30  mkunz
+ *	New Flag ChgBcPrio (Change priority of last broadcast received)
+ *
+ *	Revision 1.61  2001/03/14 12:52:08  rassmann
+ *	Fixed reporting of active port up/down to PNMI.
+ *
+ *	Revision 1.60  2001/02/21 16:02:25  gklug
+ *	fix: when RLMT starts set Active Port for PNMI
+ *
+ *	Revision 1.59  2001/02/16 14:38:19  rassmann
+ *	Initializing some pointers earlier in the init phase.
+ *	Rx Mbufs are freed if the net which they belong to is stopped.
+ *
+ *	Revision 1.58  2001/02/14 14:06:31  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.57  2001/02/05 14:25:26  rassmann
+ *	Prepared RLMT for transparent operation.
+ *
+ *	Revision 1.56  2001/01/30 10:29:09  rassmann
+ *	Not checking switching befor RlmtStart.
+ *	Editorial changes.
+ *
+ *	Revision 1.55  2001/01/22 13:41:38  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *
+ *	Revision 1.54  2000/11/30 13:25:07  rassmann
+ *	Setting SK_TICK_INCR to 1 by default.
+ *
+ *	Revision 1.53  2000/11/30 10:48:07  cgoos
+ *	Changed definition of SK_RLMT_BC_DELTA.
+ *
+ *	Revision 1.52  2000/11/27 12:50:03  rassmann
+ *	Checking ports after receiving broadcasts.
+ *
+ *	Revision 1.51  2000/11/17 08:58:00  rassmann
+ *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event.
+ *
+ *	Revision 1.50  2000/11/09 12:24:34  rassmann
+ *	Indicating that segmentation check is not running anymore after
+ *	  SkRlmtCheckSeg().
+ *	Restarting segmentation timer after segmentation log.
+ *	Editorial changes.
+ *
+ *	Revision 1.49  1999/11/22 13:38:02  cgoos
+ *	Changed license header to GPL.
+ *	Added initialization to some variables to avoid compiler warnings.
+ *
+ *	Revision 1.48  1999/10/04 14:01:17  rassmann
+ *	Corrected reaction to reception of BPDU frames (#10441).
+ *
+ *	Revision 1.47  1999/07/20 12:53:36  rassmann
+ *	Fixed documentation errors for lookahead macros.
+ *
+ *	Revision 1.46  1999/05/28 13:29:16  rassmann
+ *	Replaced C++-style comment.
+ *
+ *	Revision 1.45  1999/05/28 13:28:08  rassmann
+ *	Corrected syntax error (xxx).
+ *
+ *	Revision 1.44  1999/05/28 11:15:54  rassmann
+ *	Changed behaviour to reflect Design Spec v1.2.
+ *	Controlling Link LED(s).
+ *	Introduced RLMT Packet Version field in RLMT Packet.
+ *	Newstyle lookahead macros (checking meta-information before looking at
+ *	  the packet).
+ *
+ *	Revision 1.43  1999/01/28 13:12:43  rassmann
+ *	Corrected Lookahead (bug introduced in previous Rev.).
+ *
+ *	Revision 1.42  1999/01/28 12:50:41  rassmann
+ *	Not using broadcast time stamps in CheckLinkState mode.
+ *
+ *	Revision 1.41  1999/01/27 14:13:02  rassmann
+ *	Monitoring broadcast traffic.
+ *	Switching more reliably and not too early if switch is
+ *	 configured for spanning tree.
+ *
+ *	Revision 1.40  1999/01/22 13:17:30  rassmann
+ *	Informing PNMI of NET_UP.
+ *	Clearing RLMT multicast addresses before setting them for the first time.
+ *	Reporting segmentation earlier, setting a "quiet time"
+ *	 after a report.
+ *
+ *	Revision 1.39  1998/12/10 15:29:53  rassmann
+ *	Corrected SuspectStatus in SkRlmtBuildCheckChain().
+ *	Corrected CHECK_SEG mode.
+ *
+ *	Revision 1.38  1998/12/08 13:11:23  rassmann
+ *	Stopping SegTimer at RlmtStop.
+ *
+ *	Revision 1.37  1998/12/07 16:51:42  rassmann
+ *	Corrected comments.
+ *
+ *	Revision 1.36  1998/12/04 10:58:56  rassmann
+ *	Setting next pointer to NULL when receiving.
+ *
+ *	Revision 1.35  1998/12/03 16:12:42  rassmann
+ *	Ignoring/correcting illegal PrefPort values.
+ *
+ *	Revision 1.34  1998/12/01 11:45:35  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.33  1998/12/01 10:29:32  rassmann
+ *	Starting standby ports before getting the net up.
+ *	Checking if a port is started when the link comes up.
+ *
+ *	Revision 1.32  1998/11/30 16:19:50  rassmann
+ *	New default for PortNoRx.
+ *
+ *	Revision 1.31  1998/11/27 19:17:13  rassmann
+ *	Corrected handling of LINK_DOWN coming shortly after LINK_UP.
+ *
+ *	Revision 1.30  1998/11/24 12:37:31  rassmann
+ *	Implemented segmentation check.
+ *
+ *	Revision 1.29  1998/11/18 13:04:32  rassmann
+ *	Secured PortUpTimer event.
+ *	Waiting longer before starting standby port(s).
+ *
+ *	Revision 1.28  1998/11/17 13:43:04  rassmann
+ *	Handling (logical) tx failure.
+ *	Sending packet on logical address after PORT_SWITCH.
+ *
+ *	Revision 1.27  1998/11/13 17:09:50  rassmann
+ *	Secured some events against being called in wrong state.
+ *
+ *	Revision 1.26  1998/11/13 16:56:54  rassmann
+ *	Added macro version of SkRlmtLookaheadPacket.
+ *
+ *	Revision 1.25  1998/11/06 18:06:04  rassmann
+ *	Corrected timing when RLMT checks fail.
+ *	Clearing tx counter earlier in periodical checks.
+ *
+ *	Revision 1.24  1998/11/05 10:37:27  rassmann
+ *	Checking destination address in Lookahead.
+ *
+ *	Revision 1.23  1998/11/03 13:53:49  rassmann
+ *	RLMT should switch now (at least in mode 3).
+ *
+ *	Revision 1.22  1998/10/29 14:34:49  rassmann
+ *	Clearing SK_RLMT struct at startup.
+ *	Initializing PortsUp during SK_RLMT_START.
+ *
+ *	Revision 1.21  1998/10/28 11:30:17  rassmann
+ *	Default mode is now SK_RLMT_CHECK_LOC_LINK.
+ *
+ *	Revision 1.20  1998/10/26 16:02:03  rassmann
+ *	Ignoring LINK_DOWN for links that are down.
+ *
+ *	Revision 1.19  1998/10/22 15:54:01  rassmann
+ *	Corrected EtherLen.
+ *	Starting Link Check when second port comes up.
+ *
+ *	Revision 1.18  1998/10/22 11:39:50  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	Corrected receive list handling and address recognition.
+ *
+ *	Revision 1.17  1998/10/19 17:01:20  rassmann
+ *	More detailed checking of received packets.
+ *
+ *	Revision 1.16  1998/10/15 15:16:34  rassmann
+ *	Finished Spanning Tree checking.
+ *	Checked with lint.
+ *
+ *	Revision 1.15  1998/09/24 19:16:07  rassmann
+ *	Code cleanup.
+ *	Introduced Timer for PORT_DOWN due to no RX.
+ *
+ *	Revision 1.14  1998/09/18 20:27:14  rassmann
+ *	Added address override.
+ *
+ *	Revision 1.13  1998/09/16 11:31:48  rassmann
+ *	Including skdrv1st.h again. :(
+ *
+ *	Revision 1.12  1998/09/16 11:09:50  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.11  1998/09/15 12:32:03  rassmann
+ *	Syntax correction.
+ *
+ *	Revision 1.10  1998/09/15 11:28:49  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.9  1998/09/14 17:07:37  rassmann
+ *	Added code for port checking via LAN.
+ *	Changed Mbuf definition.
+ *
+ *	Revision 1.8  1998/09/07 11:14:14  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.7  1998/09/07 09:06:07  rassmann
+ *	Syntax corrections.
+ *
+ *	Revision 1.6  1998/09/04 19:41:33  rassmann
+ *	Syntax corrections.
+ *	Started entering code for checking local links.
+ *
+ *	Revision 1.5  1998/09/04 12:14:27  rassmann
+ *	Interface cleanup.
+ *
+ *	Revision 1.4  1998/09/02 16:55:28  rassmann
+ *	Updated to reflect new DRV/HWAC/RLMT interface.
+ *
+ *	Revision 1.3  1998/08/27 14:29:03  rassmann
+ *	Code cleanup.
+ *
+ *	Revision 1.2  1998/08/27 14:26:24  rassmann
+ *	Updated interface.
+ *
+ *	Revision 1.1  1998/08/21 08:26:49  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
+ * It is mainly intended for adapters with more than one link.
+ * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skrlmt.c,v 1.68 2003/01/31 15:26:56 rschmidt Exp $ (C) SysKonnect.";
+#endif	/* !defined(lint) */
+
+#define __SKRLMT_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#ifndef SK_HWAC_LINK_LED
+#define SK_HWAC_LINK_LED(a,b,c,d)
+#endif	/* !defined(SK_HWAC_LINK_LED) */
+
+#ifndef DEBUG
+#define RLMT_STATIC	static
+#else	/* DEBUG */
+#define RLMT_STATIC
+
+#ifndef SK_LITTLE_ENDIAN
+/* First 32 bits */
+#define OFFS_LO32	1
+
+/* Second 32 bits */
+#define OFFS_HI32	0
+#else	/* SK_LITTLE_ENDIAN */
+/* First 32 bits */
+#define OFFS_LO32	0
+
+/* Second 32 bits */
+#define OFFS_HI32	1
+#endif	/* SK_LITTLE_ENDIAN */
+
+#endif	/* DEBUG */
+
+/* ----- Private timeout values ----- */
+
+#define SK_RLMT_MIN_TO_VAL			   125000	/* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL			  1000000	/* 1 sec. */
+#define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */
+#define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */
+#define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */
+#define SK_RLMT_SEG_TO_VAL			900000000	/* 15 min. */
+
+/* Assume tick counter increment is 1 - may be set OS-dependent. */
+#ifndef SK_TICK_INCR
+#define SK_TICK_INCR	SK_CONSTU64(1)
+#endif	/* !defined(SK_TICK_INCR) */
+
+/*
+ * Amount that a time stamp must be later to be recognized as "substantially
+ * later". This is about 1/128 sec, but above 1 tick counter increment.
+ */
+#define SK_RLMT_BC_DELTA		(1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
+									(SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
+
+/* ----- Private RLMT defaults ----- */
+
+#define SK_RLMT_DEF_PREF_PORT	0					/* "Lower" port. */
+#define SK_RLMT_DEF_MODE 		SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
+
+/* ----- Private RLMT checking states ----- */
+
+#define SK_RLMT_RCS_SEG			1		/* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG	2		/* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG	4		/* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG	8		/* RLMT Check State: report seg. */
+
+/* ----- Private PORT checking states ----- */
+
+#define SK_RLMT_PCS_TX			1		/* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX			2		/* Port Check State: check rx. */
+
+/* ----- Private PORT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */
+#define SK_RLMT_PORTUP_TIM		1101	/* Port can now go up. */
+#define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */
+#define SK_RLMT_PORTDOWN		1103	/* Port went down. */
+#define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */
+
+/* ----- Private RLMT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_TIM				2100	/* RLMT timeout. */
+#define SK_RLMT_SEG_TIM			2101	/* RLMT segmentation check timeout. */
+
+#define TO_SHORTEN(tim)	((tim) / 2)
+
+/* Error numbers and messages. */
+#define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0)
+#define SKERR_RLMT_E001_MSG	"No Packet."
+#define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1)
+#define SKERR_RLMT_E002_MSG	"Short Packet."
+#define SKERR_RLMT_E003		(SKERR_RLMT_E002 + 1)
+#define SKERR_RLMT_E003_MSG	"Unknown RLMT event."
+#define SKERR_RLMT_E004		(SKERR_RLMT_E003 + 1)
+#define SKERR_RLMT_E004_MSG	"PortsUp incorrect."
+#define SKERR_RLMT_E005		(SKERR_RLMT_E004 + 1)
+#define SKERR_RLMT_E005_MSG	\
+ "Net seems to be segmented (different root bridges are reported on the ports)."
+#define SKERR_RLMT_E006		(SKERR_RLMT_E005 + 1)
+#define SKERR_RLMT_E006_MSG	"Duplicate MAC Address detected."
+#define SKERR_RLMT_E007		(SKERR_RLMT_E006 + 1)
+#define SKERR_RLMT_E007_MSG	"LinksUp incorrect."
+#define SKERR_RLMT_E008		(SKERR_RLMT_E007 + 1)
+#define SKERR_RLMT_E008_MSG	"Port not started but link came up."
+#define SKERR_RLMT_E009		(SKERR_RLMT_E008 + 1)
+#define SKERR_RLMT_E009_MSG	"Corrected illegal setting of Preferred Port."
+#define SKERR_RLMT_E010		(SKERR_RLMT_E009 + 1)
+#define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port."
+
+/* LLC field values. */
+#define LLC_COMMAND_RESPONSE_BIT		1
+#define LLC_TEST_COMMAND				0xE3
+#define LLC_UI							0x03
+
+/* RLMT Packet fields. */
+#define	SK_RLMT_DSAP					0
+#define	SK_RLMT_SSAP					0
+#define SK_RLMT_CTRL					(LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0				0x53	/* S */
+#define SK_RLMT_INDICATOR1				0x4B	/* K */
+#define SK_RLMT_INDICATOR2				0x2D	/* - */
+#define SK_RLMT_INDICATOR3				0x52	/* R */
+#define SK_RLMT_INDICATOR4				0x4C	/* L */
+#define SK_RLMT_INDICATOR5				0x4D	/* M */
+#define SK_RLMT_INDICATOR6				0x54	/* T */
+#define SK_RLMT_PACKET_VERSION			0
+
+/* RLMT SPT Flag values. */
+#define	SK_RLMT_SPT_FLAG_CHANGE			0x01
+#define	SK_RLMT_SPT_FLAG_CHANGE_ACK		0x80
+
+/* RLMT SPT Packet fields. */
+#define	SK_RLMT_SPT_DSAP				0x42
+#define	SK_RLMT_SPT_SSAP				0x42
+#define SK_RLMT_SPT_CTRL				(LLC_UI)
+#define	SK_RLMT_SPT_PROTOCOL_ID0		0x00
+#define	SK_RLMT_SPT_PROTOCOL_ID1		0x00
+#define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00
+#define	SK_RLMT_SPT_BPDU_TYPE			0x00
+#define	SK_RLMT_SPT_FLAGS				0x00	/* ?? */
+#define	SK_RLMT_SPT_ROOT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_ROOT_ID1			0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define	SK_RLMT_SPT_ROOT_PATH_COST0		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST1		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST2		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST3		0x00
+#define	SK_RLMT_SPT_BRIDGE_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_BRIDGE_ID1			0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define	SK_RLMT_SPT_PORT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_PORT_ID1			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_MSG_AGE0			0x00
+#define	SK_RLMT_SPT_MSG_AGE1			0x00
+#define	SK_RLMT_SPT_MAX_AGE0			0x00
+#define	SK_RLMT_SPT_MAX_AGE1			0xFF
+#define	SK_RLMT_SPT_HELLO_TIME0			0x00
+#define	SK_RLMT_SPT_HELLO_TIME1			0xFF
+#define	SK_RLMT_SPT_FWD_DELAY0			0x00
+#define	SK_RLMT_SPT_FWD_DELAY1			0x40
+
+/* Size defines. */
+#define SK_RLMT_MIN_PACKET_SIZE			34
+#define SK_RLMT_MAX_PACKET_SIZE			(SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN				(SK_RLMT_MAX_PACKET_SIZE - \
+										SK_RLMT_MIN_PACKET_SIZE)
+
+/* ----- RLMT packet types ----- */
+#define SK_PACKET_ANNOUNCE				1	/* Port announcement. */
+#define SK_PACKET_ALIVE					2	/* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED			3	/* Port address changed. */
+#define SK_PACKET_CHECK_TX				4	/* Check your tx line. */
+
+#ifdef SK_LITTLE_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
+	SK_U8	*_Addr = (SK_U8*)(Addr); \
+	SK_U16	_Val = (SK_U16)(Val); \
+	*_Addr++ = (SK_U8)(_Val >> 8); \
+	*_Addr = (SK_U8)(_Val & 0xFF); \
+}
+#endif	/* SK_LITTLE_ENDIAN */
+
+#ifdef SK_BIG_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
+#endif	/* SK_BIG_ENDIAN */
+
+#define AUTONEG_FAILED	SK_FALSE
+#define AUTONEG_SUCCESS	SK_TRUE
+
+
+/* typedefs *******************************************************************/
+
+/* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
+typedef struct s_RlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	Indicator[7];
+	SK_U8	RlmtPacketType[2];
+	SK_U8	Align1[2];
+	SK_U8	Random[4];				/* Random value of requesting(!) station. */
+	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version. */
+	SK_U8	Data[SK_PACKET_DATA_LEN];
+} SK_RLMT_PACKET;
+
+typedef struct s_SpTreeRlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	ProtocolId[2];
+	SK_U8	ProtocolVersionId;
+	SK_U8	BpduType;
+	SK_U8	Flags;
+	SK_U8	RootId[8];
+	SK_U8	RootPathCost[4];
+	SK_U8	BridgeId[8];
+	SK_U8	PortId[2];
+	SK_U8	MessageAge[2];
+	SK_U8	MaxAge[2];
+	SK_U8	HelloTime[2];
+	SK_U8	ForwardDelay[2];
+} SK_SPTREE_PACKET;
+
+/* global variables ***********************************************************/
+
+SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
+SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
+SK_MAC_ADDR	BcAddr = 		{{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
+
+/* local variables ************************************************************/
+
+/* None. */
+
+/* functions ******************************************************************/
+
+RLMT_STATIC void	SkRlmtCheckSwitch(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
+RLMT_STATIC void	SkRlmtCheckSeg(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
+RLMT_STATIC void	SkRlmtEvtSetNets(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_EVPARA	Para);
+
+/******************************************************************************
+ *
+ *	SkRlmtInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine initializes all RLMT-related variables to a known state.
+ *	The initial state is SK_RLMT_RS_INIT.
+ *	All ports are initialized to SK_RLMT_PS_INIT.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	Nothing.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Determine the adapter's random value.
+ *	Set the hw registers, the "logical MAC address", the
+ *	RLMT multicast address, and eventually the BPDU multicast address.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	Nothing.
+ */
+void	SkRlmtInit(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+int		Level)	/* Initialization Level */
+{
+	SK_U32		i, j;
+	SK_U64		Random;
+	SK_EVPARA	Para;
+    SK_MAC_ADDR		VirtualMacAddress;
+    SK_MAC_ADDR		PhysicalAMacAddress;
+    SK_BOOL		VirtualMacAddressSet;
+    SK_BOOL		PhysicalAMacAddressSet;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+		("RLMT Init level %d.\n", Level))
+
+	switch (Level) {
+	case SK_INIT_DATA:	/* Initialize data structures. */
+		SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
+			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Port[i].PortNumber = i;
+			pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
+			pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
+		}
+
+		pAC->Rlmt.NumNets = 1;
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
+		pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
+#if SK_MAX_NETS > 1
+		pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
+#endif	/* SK_MAX_NETS > 1 */
+		break;
+
+	case SK_INIT_IO:	/* GIMacsFound first available here. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+			("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
+
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+		/* Initialize HW registers? */
+		if (pAC->GIni.GIMacsFound == 1) {
+			Para.Para32[0] = SK_RLMT_MODE_CLS;
+			Para.Para32[1] = 0;
+			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
+		}
+		break;
+
+	case SK_INIT_RUN:
+		/* Ensure RLMT is set to one net. */
+		if (pAC->Rlmt.NumNets > 1) {
+			Para.Para32[0] = 1;
+			Para.Para32[1] = -1;
+			SkRlmtEvtSetNets(pAC, IoC, Para);
+		}
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			Random = SkOsGetTime(pAC);
+			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
+
+			for (j = 0; j < 4; j++) {
+				pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
+					CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
+			}
+
+			(void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+			if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
+				/* Add BPDU MC address. */
+				(void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
+			}
+
+			(void)SkAddrMcUpdate(pAC, IoC, i);
+		}
+
+	VirtualMacAddressSet = SK_FALSE;
+		/* Read virtual MAC address from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+
+	    SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]);
+	    VirtualMacAddressSet |= VirtualMacAddress.a[j];
+		}
+
+	PhysicalAMacAddressSet = SK_FALSE;
+		/* Read physical MAC address for MAC A from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+
+	    SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]);
+	    PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j];
+		}
+
+	/* check if the two mac addresses contain reasonable values */
+	if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) {
+
+	    pAC->Rlmt.RlmtOff = SK_TRUE;
+	}
+
+	/* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD
+	   and the RLMT_LOOKAHEAD macros */
+	else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) {
+
+	    pAC->Rlmt.RlmtOff = SK_TRUE;
+	}
+		else {
+			pAC->Rlmt.RlmtOff = SK_FALSE;
+		}
+		break;
+
+	default:	/* error */
+		break;
+	}
+	return;
+}	/* SkRlmtInit */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildCheckChain - build the check chain
+ *
+ * Description:
+ *	This routine builds the local check chain:
+ *	- Each port that is up checks the next port.
+ *	- The last port that is up checks the first port that is up.
+ *
+ * Notes:
+ *	- Currently only local ports are considered when building the chain.
+ *	- Currently the SuspectState is just reset;
+ *	  it would be better to save it ...
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtBuildCheckChain(
+SK_AC	*pAC,	/* Adapter Context */
+SK_U32	NetIdx)	/* Net Number */
+{
+	SK_U32			i;
+	SK_U32			NumMacsUp;
+	SK_RLMT_PORT *	FirstMacUp;
+	SK_RLMT_PORT *	PrevMacUp;
+
+	FirstMacUp	= NULL;
+	PrevMacUp	= NULL;
+
+	if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
+			pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+		}
+		return;	/* Done. */
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SkRlmtBuildCheckChain.\n"))
+
+	NumMacsUp = 0;
+
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
+			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
+
+		/*
+		 * If more than two links are detected we should consider
+		 * checking at least two other ports:
+		 * 1. the next port that is not LinkDown and
+		 * 2. the next port that is not PortDown.
+		 */
+		if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+			if (NumMacsUp == 0) {
+				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+			}
+			else {
+				PrevMacUp->PortCheck[
+					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
+					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
+				PrevMacUp->PortCheck[
+					PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
+				PrevMacUp->PortsChecked++;
+			}
+			PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+			NumMacsUp++;
+		}
+	}
+
+	if (NumMacsUp > 1) {
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
+			FirstMacUp->AddrPort->CurrentMacAddress;
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
+			SK_FALSE;
+		PrevMacUp->PortsChecked++;
+	}
+
+#ifdef DEBUG
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d checks %d other ports: %2X.\n", i,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
+	}
+#endif	/* DEBUG */
+
+	return;
+}	/* SkRlmtBuildCheckChain */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildPacket - build an RLMT packet
+ *
+ * Description:
+ *	This routine sets up an RLMT packet.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* I/O Context */
+SK_U32		PortNumber,	/* Sending port */
+SK_U16		PacketType,	/* RLMT packet type */
+SK_MAC_ADDR	*SrcAddr,	/* Source address */
+SK_MAC_ADDR	*DestAddr)	/* Destination address */
+{
+	int		i;
+	SK_U16		Length;
+	SK_MBUF		*pMb;
+	SK_RLMT_PACKET	*pPacket;
+
+#ifdef DEBUG
+	SK_U8	CheckSrc  = 0;
+	SK_U8	CheckDest = 0;
+
+	for (i = 0; i < SK_MAC_ADDR_LEN; ++i) {
+		CheckSrc  |= SrcAddr->a[i];
+		CheckDest |= DestAddr->a[i];
+	}
+
+	if ((CheckSrc == 0) || (CheckDest == 0)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR,
+			("SkRlmtBuildPacket: Invalid %s%saddr.\n",
+			 (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : "")))
+	}
+#endif
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
+		pPacket = (SK_RLMT_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pPacket->DstAddr[i] = DestAddr->a[i];
+			pPacket->SrcAddr[i] = SrcAddr->a[i];
+		}
+		pPacket->DSap = SK_RLMT_DSAP;
+		pPacket->SSap = SK_RLMT_SSAP;
+		pPacket->Ctrl = SK_RLMT_CTRL;
+		pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
+		pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
+		pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
+		pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
+		pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
+		pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
+		pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
+
+		SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
+
+		for (i = 0; i < 4; i++) {
+			pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
+		}
+
+		SK_U16_TO_NETWORK_ORDER(
+			SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
+
+		for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
+			pPacket->Data[i] = 0x00;
+		}
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortNumber;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
+
+		if (PacketType == SK_PACKET_ALIVE) {
+			pAC->Rlmt.Port[PortNumber].TxHelloCts++;
+		}
+	}
+
+	return (pMb);
+}	/* SkRlmtBuildPacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildSpanningTreePacket - build spanning tree check packet
+ *
+ * Description:
+ *	This routine sets up a BPDU packet for spanning tree check.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
+{
+	unsigned			i;
+	SK_U16				Length;
+	SK_MBUF				*pMb;
+	SK_SPTREE_PACKET	*pSPacket;
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+		NULL) {
+		pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
+			pSPacket->SrcAddr[i] =
+				pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+		}
+		pSPacket->DSap = SK_RLMT_SPT_DSAP;
+		pSPacket->SSap = SK_RLMT_SPT_SSAP;
+		pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
+
+		pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
+		pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
+		pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
+		pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
+		pSPacket->Flags = SK_RLMT_SPT_FLAGS;
+		pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
+		pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
+		pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
+		pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
+		pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
+		pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
+		pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
+		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
+
+		/*
+		 * Use logical MAC address as bridge ID and filter these packets
+		 * on receive.
+		 */
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
+				pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
+					CurrentMacAddress.a[i];
+		}
+		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
+		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
+		pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
+		pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
+		pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
+		pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
+		pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
+		pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
+		pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
+		pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortNumber;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
+
+		pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
+	}
+
+	return (pMb);
+}	/* SkRlmtBuildSpanningTreePacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSend - build and send check packets
+ *
+ * Description:
+ *	Depending on the RLMT state and the checking state, several packets
+ *	are sent through the indicated port.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtSend(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
+{
+	unsigned	j;
+	SK_EVPARA	Para;
+	SK_RLMT_PORT	*pRPort;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+	if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+		if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+			/* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+		}
+		else {
+			/*
+			 * Send a directed RLMT packet to all ports that are
+			 * checked by the indicated port.
+			 */
+			for (j = 0; j < pRPort->PortsChecked; j++) {
+				if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+					SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+					&pRPort->PortCheck[j].CheckAddr)) != NULL) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+				}
+			}
+		}
+	}
+
+	if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
+		/*
+		 * Send a BPDU packet to make a connected switch tell us
+		 * the correct root bridge.
+		 */
+		if ((Para.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+			pRPort->RootIdSet = SK_FALSE;
+
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
+				("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
+		}
+	}
+	return;
+}	/* SkRlmtSend */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortReceives - check if port is (going) down and bring it up
+ *
+ * Description:
+ *	This routine checks if a port who received a non-BPDU packet
+ *	needs to go up or needs to be stopped going down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPortReceives(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	PortNumber)		/* Port to check */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+	pRPort->PortNoRx = SK_FALSE;
+
+	if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
+		/*
+		 * Port is marked down (rx), but received a non-BPDU packet.
+		 * Bring it up.
+		 */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Received on PortDown.\n"))
+
+		pRPort->PortState = SK_RLMT_PS_GOING_UP;
+		pRPort->GuTimeStamp = SkOsGetTime(pAC);
+		Para.Para32[0] = PortNumber;
+		Para.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+			SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortDown && !SuspectTx */
+	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Stop bringing port down.\n"))
+		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortGoingDown */
+
+	return;
+}	/* SkRlmtPortReceives */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPacketReceive - receive a packet for closer examination
+ *
+ * Description:
+ *	This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPacketReceive(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_MBUF	*pMb)	/* Received packet */
+{
+#ifdef xDEBUG
+	extern	void DumpData(char *p, int size);
+#endif	/* DEBUG */
+	int					i;
+	unsigned			j;
+	SK_U16				PacketType;
+	SK_U32				PortNumber;
+	SK_ADDR_PORT		*pAPort;
+	SK_RLMT_PORT		*pRPort;
+	SK_RLMT_PACKET		*pRPacket;
+	SK_SPTREE_PACKET	*pSPacket;
+	SK_EVPARA			Para;
+
+	PortNumber	= pMb->PortIdx;
+	pAPort = &pAC->Addr.Port[PortNumber];
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+		("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
+
+	pRPacket = (SK_RLMT_PACKET*)pMb->pData;
+	pSPacket = (SK_SPTREE_PACKET*)pRPacket;
+
+#ifdef xDEBUG
+	DumpData((char *)pRPacket, 32);
+#endif	/* DEBUG */
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
+	}
+
+	/* Check destination address. */
+
+	if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
+
+		/* Not sent to current MAC or registered MC address => Trash it. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Not for me.\n"))
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		return;
+	}
+	else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
+
+		/*
+		 * Was sent by same port (may happen during port switching
+		 * or in case of duplicate MAC addresses).
+		 */
+
+		/*
+		 * Check for duplicate address here:
+		 * If Packet.Random != My.Random => DupAddr.
+		 */
+		for (i = 3; i >= 0; i--) {
+			if (pRPort->Random[i] != pRPacket->Random[i]) {
+				break;
+			}
+		}
+
+		/*
+		 * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
+		 * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
+		 * pRPacket->SSap).
+		 */
+		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
+			pRPacket->Ctrl == SK_RLMT_CTRL &&
+			pRPacket->SSap == SK_RLMT_SSAP &&
+			pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+			pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+			pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+			pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
+
+			/* Error Log entry. */
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
+		}
+		else {
+			/* Simply trash it. */
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Sent by me.\n"))
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		return;
+	}
+
+	/* Check SuspectTx entries. */
+	if (pRPort->PortsSuspect > 0) {
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (pRPort->PortCheck[j].SuspectTx &&
+				SK_ADDR_EQUAL(
+					pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
+				pRPort->PortCheck[j].SuspectTx = SK_FALSE;
+				pRPort->PortsSuspect--;
+				break;
+			}
+		}
+	}
+
+	/* Determine type of packet. */
+	if (pRPacket->DSap == SK_RLMT_DSAP &&
+		pRPacket->Ctrl == SK_RLMT_CTRL &&
+		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
+		pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+		pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+		pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+		pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+		pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+		pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+
+		/* It's an RLMT packet. */
+		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
+			pRPacket->RlmtPacketType[1]);
+
+		switch (PacketType) {
+		case SK_PACKET_ANNOUNCE:	/* Not yet used. */
+#if 0
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC);
+#endif	/* 0 */
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Announce.\n"))
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		case SK_PACKET_ALIVE:
+			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Reply.\n"))
+
+				if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
+					SK_ADDR_EQUAL(
+						pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
+					/* Obviously we could send something. */
+					if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
+						pRPort->CheckingState &=  ~SK_RLMT_PCS_TX;
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+					}
+
+					if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+						!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+						pRPort->PortState = SK_RLMT_PS_GOING_UP;
+						pRPort->GuTimeStamp = SkOsGetTime(pAC);
+
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+						Para.Para32[0] = PortNumber;
+						Para.Para32[1] = (SK_U32)-1;
+						SkTimerStart(pAC, IoC, &pRPort->UpTimer,
+							SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
+							SK_RLMT_PORTUP_TIM, Para);
+					}
+				}
+
+				/* Mark sending port as alive? */
+				SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			}
+			else {	/* Alive Request Packet. */
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Request.\n"))
+
+				pRPort->RxHelloCts++;
+
+				/* Answer. */
+				for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+					pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
+					pRPacket->SrcAddr[i] =
+						pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+				}
+				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
+
+				Para.pParaPtr = pMb;
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+			break;
+
+		case SK_PACKET_CHECK_TX:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Check your tx line.\n"))
+
+			/* A port checking us requests us to check our tx line. */
+			pRPort->CheckingState |= SK_RLMT_PCS_TX;
+
+			/* Start PortDownTx timer. */
+			Para.Para32[0] = PortNumber;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
+				SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+				SK_RLMT_PORTDOWN_TX_TIM, Para);
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+			break;
+
+		case SK_PACKET_ADDR_CHANGED:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Address Change.\n"))
+
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
+
+			/* RA;:;: ??? */
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+	}
+	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
+		pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
+		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: BPDU Packet.\n"))
+
+		/* Spanning Tree packet. */
+		pRPort->RxSpHelloCts++;
+
+		if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
+			Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
+			/*
+			 * Check segmentation if a new root bridge is set and
+			 * the segmentation check is not currently running.
+			 */
+			if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
+				(pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+				(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
+				!= 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+				SK_RLMT_RCS_SEG) == 0) {
+				pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+					SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+			}
+
+			/* Store tree view of this port. */
+			for (i = 0; i < 8; i++) {
+				pRPort->Root.Id[i] = pSPacket->RootId[i];
+			}
+			pRPort->RootIdSet = SK_TRUE;
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+				("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+					PortNumber,
+					pRPort->Root.Id[0], pRPort->Root.Id[1],
+					pRPort->Root.Id[2], pRPort->Root.Id[3],
+					pRPort->Root.Id[4], pRPort->Root.Id[5],
+					pRPort->Root.Id[6], pRPort->Root.Id[7]))
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+			SK_RLMT_RCS_REPORT_SEG) != 0) {
+			SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
+		}
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Unknown Packet Type.\n"))
+
+		/* Unknown packet. */
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+	}
+	return;
+}	/* SkRlmtPacketReceive */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckPort - check if a port works
+ *
+ * Description:
+ *	This routine checks if a port whose link is up received something
+ *	and if it seems to transmit successfully.
+ *
+ *	# PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
+ *	# PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
+ *	# RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
+ *
+ *	if (Rx - RxBpdu == 0) {	# No rx.
+ *		if (state == PsUp) {
+ *			PortCheckingState |= ChkRx
+ *		}
+ *		if (ModeCheckSeg && (Timeout ==
+ *			TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
+ *			RlmtCheckingState |= ChkSeg)
+ *			PortCheckingState |= ChkSeg
+ *		}
+ *		NewTimeout = TO_SHORTEN(Timeout)
+ *		if (NewTimeout < RLMT_MIN_TIMEOUT) {
+ *			NewTimeout = RLMT_MIN_TIMEOUT
+ *			PortState = PsDown
+ *			...
+ *		}
+ *	}
+ *	else {	# something was received
+ *		# Set counter to 0 at LinkDown?
+ *		#   No - rx may be reported after LinkDown ???
+ *		PortCheckingState &= ~ChkRx
+ *		NewTimeout = RLMT_DEFAULT_TIMEOUT
+ *		if (RxAck == 0) {
+ *			possible reasons:
+ *			is my tx line bad? --
+ *				send RLMT multicast and report
+ *				back internally? (only possible
+ *				between ports on same adapter)
+ *		}
+ *		if (RxChk == 0) {
+ *			possible reasons:
+ *			- tx line of port set to check me
+ *			  maybe bad
+ *			- no other port/adapter available or set
+ *			  to check me
+ *			- adapter checking me has a longer
+ *			  timeout
+ *			??? anything that can be done here?
+ *		}
+ *	}
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	New timeout value.
+ */
+RLMT_STATIC SK_U32	SkRlmtCheckPort(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port to check */
+{
+	unsigned		i;
+	SK_U32			NewTimeout;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
+				PortNumber, pRPort->PacketsPerTimeSlot))
+
+		/*
+		 * Check segmentation if there was no receive at least twice
+		 * in a row (PortNoRx is already set) and the segmentation
+		 * check is not currently running.
+		 */
+
+		if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+			(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+			!(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+		}
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
+				pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
+
+		if (pRPort->PortState != SK_RLMT_PS_DOWN) {
+			NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
+			if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
+				NewTimeout = SK_RLMT_MIN_TO_VAL;
+			}
+
+			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+				Para.Para32[0] = PortNumber;
+				pRPort->CheckingState |= SK_RLMT_PCS_RX;
+
+				/*
+				 * What shall we do if the port checked by this one receives
+				 * our request frames?  What's bad - our rx line or his tx line?
+				 */
+				Para.Para32[1] = (SK_U32)-1;
+				SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
+					SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+					SK_RLMT_PORTDOWN_RX_TIM, Para);
+
+				for (i = 0; i < pRPort->PortsChecked; i++) {
+					if (pRPort->PortCheck[i].SuspectTx) {
+						continue;
+					}
+					pRPort->PortCheck[i].SuspectTx = SK_TRUE;
+					pRPort->PortsSuspect++;
+					if ((Para.pParaPtr =
+						SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
+							&pAC->Addr.Port[PortNumber].CurrentMacAddress,
+							&pRPort->PortCheck[i].CheckAddr)) != NULL) {
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+					}
+				}
+			}
+		}
+		else {	/* PortDown -- or all partners suspect. */
+			NewTimeout = SK_RLMT_DEF_TO_VAL;
+		}
+		pRPort->PortNoRx = SK_TRUE;
+	}
+	else {	/* A non-BPDU packet was received. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
+				PortNumber,
+				pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
+				pRPort->PacketsPerTimeSlot))
+
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
+		if (pAC->Rlmt.CheckSwitch) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+
+		NewTimeout = SK_RLMT_DEF_TO_VAL;
+	}
+
+	return (NewTimeout);
+}	/* SkRlmtCheckPort */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that received a broadcast frame
+ *	substantially later than all other ports.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
+{
+	SK_U64		BcTimeStamp;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
+	PortFound = SK_FALSE;
+
+	/* Select port with the latest TimeStamp. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n",
+				i,
+				pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx,
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+
+		if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
+			if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
+				*pSelect = i;
+				PortFound = SK_TRUE;
+			}
+		}
+	}
+
+	if (PortFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d received the last broadcast.\n", *pSelect))
+
+		/* Look if another port's time stamp is similar. */
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (i == *pSelect) {
+				continue;
+			}
+			if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
+				(pAC->Rlmt.Port[i].BcTimeStamp >
+				 BcTimeStamp - SK_RLMT_BC_DELTA ||
+				pAC->Rlmt.Port[i].BcTimeStamp +
+				 SK_RLMT_BC_DELTA > BcTimeStamp)) {
+				PortFound = SK_FALSE;
+
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Port %d received a broadcast at a similar time.\n", i))
+				break;
+			}
+		}
+	}
+
+#ifdef DEBUG
+	if (PortFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially "
+			 "latest broadcast (%u).\n",
+				*pSelect,
+				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
+	}
+#endif	/* DEBUG */
+
+	return (PortFound);
+}	/* SkRlmtSelectBcRx */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
+ *
+ * Description:
+ *	This routine selects a good port (it is PortUp && !SuspectRx).
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp && !SuspectRx. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (!pAC->Rlmt.Port[i].PortDown &&
+			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
+			*pSelect = i;
+			if (!pAC->Rlmt.Port[Active].PortDown &&
+				!(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = Active;
+			}
+			if (!pAC->Rlmt.Port[PrefPort].PortDown &&
+				!(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n",
+					*pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectNotSuspect */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is up.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectUp(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that is going up for the longest time.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U64		GuTimeStamp;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	GuTimeStamp = 0;
+	PortFound = SK_FALSE;
+
+	/* Select port that is PortGoingUp for the longest time. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
+			PortFound = SK_TRUE;
+			break;
+		}
+	}
+
+	if (!PortFound) {
+		return (SK_FALSE);
+	}
+
+	for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+			pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect))
+	return (SK_TRUE);
+}	/* SkRlmtSelectGoingUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectDown(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortDown. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSwitch - select new active port and switch to it
+ *
+ * Description:
+ *	This routine decides which port should be the active one and queues
+ *	port switching if necessary.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSwitch(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net index */
+{
+	SK_EVPARA	Para;
+	SK_U32		Active;
+	SK_U32		PrefPort;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	Active = pAC->Rlmt.Net[NetIdx].ActivePort;	/* Index of active port. */
+	PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;	/* Index of preferred port. */
+	PortFound = SK_FALSE;
+	pAC->Rlmt.CheckSwitch = SK_FALSE;
+
+#if 0	/* RW 2001/10/18 - active port becomes always prefered one */
+	if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */
+		/* disable auto-fail back */
+		PrefPort = Active;
+	}
+#endif
+
+	if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
+		/* Last link went down - shut down the net. */
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
+		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
+
+		Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+			Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+		return;
+	}	/* pAC->Rlmt.LinksUp == 0 */
+	else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
+		pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
+		/* First link came up - get the net up. */
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
+
+		/*
+		 * If pAC->Rlmt.ActivePort != Para.Para32[0],
+		 * the DRV switches to the port that came up.
+		 */
+		for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+				if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
+					i = Active;
+				}
+				if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
+					i = PrefPort;
+				}
+				PortFound = SK_TRUE;
+				break;
+			}
+		}
+
+		if (PortFound) {
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+
+			pAC->Rlmt.Net[NetIdx].ActivePort = i;
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
+
+			if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+				(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
+				SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
+				CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
+				/*
+				 * Send announce packet to RLMT multicast address to force
+				 * switches to learn the new location of the logical MAC address.
+				 */
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
+		}
+
+		return;
+	}	/* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
+	else {	/* Cannot be reached in dual-net mode. */
+		Para.Para32[0] = Active;
+
+		/*
+		 * Preselection:
+		 *	If RLMT Mode != CheckLinkState
+		 *		select port that received a broadcast frame substantially later
+		 *		than all other ports
+		 *	else select first port that is not SuspectRx
+		 *	else select first port that is PortUp
+		 *	else select port that is PortGoingUp for the longest time
+		 *	else select first port that is PortDown
+		 *	else stop.
+		 *
+		 * For the preselected port:
+		 *	If ActivePort is equal in quality, select ActivePort.
+		 *
+		 *	If PrefPort is equal in quality, select PrefPort.
+		 *
+		 *	If ActivePort != SelectedPort,
+		 *		If old ActivePort is LinkDown,
+		 *			SwitchHard
+		 *		else
+		 *			SwitchSoft
+		 */
+		/* check of ChgBcPrio flag added */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(!pAC->Rlmt.Net[0].ChgBcPrio)) {
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		/* with changed priority for last broadcast received */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(pAC->Rlmt.Net[0].ChgBcPrio)) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		if (PortFound) {
+
+			if (Para.Para32[1] != Active) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
+				pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[0]]->PortNumber;
+				Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[1]]->PortNumber;
+				SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
+				if (pAC->Rlmt.Port[Active].LinkDown) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
+				}
+				else {
+					SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
+				}
+				Para.Para32[1] = NetIdx;
+				Para.Para32[0] =
+					pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+				if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+					(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
+					SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
+					&SkRlmtMcAddr)) != NULL) {
+					/*
+					 * Send announce packet to RLMT multicast address to force
+					 * switches to learn the new location of the logical
+					 * MAC address.
+					 */
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+				}	/* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
+			}	/* Para.Para32[1] != Active */
+		}	/* PortFound */
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
+		}
+	}	/* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
+	return;
+}	/* SkRlmtCheckSwitch */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSeg - Report if segmentation is detected
+ *
+ * Description:
+ *	This routine checks if the ports see different root bridges and reports
+ *	segmentation in such a case.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSeg(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net number */
+{
+	SK_EVPARA	Para;
+	SK_RLMT_NET	*pNet;
+	SK_U32		i, j;
+	SK_BOOL		Equal;
+
+	pNet = &pAC->Rlmt.Net[NetIdx];
+	pNet->RootIdSet = SK_FALSE;
+	Equal = SK_TRUE;
+
+	for (i = 0; i < pNet->NumPorts; i++) {
+		if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
+			continue;
+		}
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
+				pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
+				pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
+				pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
+				pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
+
+		if (!pNet->RootIdSet) {
+			pNet->Root = pNet->Port[i]->Root;
+			pNet->RootIdSet = SK_TRUE;
+			continue;
+		}
+
+		for (j = 0; j < 8; j ++) {
+			Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
+			if (!Equal) {
+				break;
+			}
+		}
+
+		if (!Equal) {
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
+
+			pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+
+			/* 2000-03-06 RA: New. */
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
+				SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+			break;
+		}
+	}	/* for (i = 0; i < pNet->NumPorts; i++) */
+
+	/* 2000-03-06 RA: Moved here. */
+	/* Segmentation check not running anymore. */
+	pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
+
+}	/* SkRlmtCheckSeg */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortStart - initialize port variables and start port
+ *
+ * Description:
+ *	This routine initializes a port's variables and issues a PORT_START
+ *	to the HWAC module.  This handles retries if the start fails or the
+ *	link eventually goes down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtPortStart(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port number */
+{
+	SK_EVPARA	Para;
+
+	pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
+	pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].CheckingState = 0;
+	pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+	Para.Para32[0] = PortNumber;
+	Para.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+}	/* SkRlmtPortStart */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortStartTim - PORT_START_TIM
+ *
+ * Description:
+ *	This routine handles PORT_START_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortStartTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_U32			i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
+
+		if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
+		return;
+	}
+
+	/*
+	 * Used to start non-preferred ports if the preferred one
+	 * does not come up.
+	 * This timeout needs only be set when starting the first
+	 * (preferred) port.
+	 */
+	if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		/* PORT_START failed. */
+		for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
+			if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
+				SkRlmtPortStart(pAC, IoC,
+					pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
+			}
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
+}	/* SkRlmtEvtPortStartTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkUp - LINK_UP
+ *
+ * Description:
+ *	This routine handles LLINK_UP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkUp(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
+
+	if (!pRPort->LinkDown) {
+		/* RA;:;: Any better solution? */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
+
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+	/* Do something if timer already fired? */
+
+	pRPort->LinkDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_GOING_UP;
+	pRPort->GuTimeStamp = SkOsGetTime(pAC);
+	pRPort->BcTimeStamp = 0;
+	pRPort->Net->LinksUp++;
+	if (pRPort->Net->LinksUp == 1) {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
+	}
+	else {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+	}
+
+	for (i = 0; i < pRPort->Net->NumPorts; i++) {
+		if (!pRPort->Net->Port[i]->PortStarted) {
+			SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
+		}
+	}
+
+	SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+
+	if (pRPort->Net->LinksUp >= 2) {
+		if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+		}
+	}
+
+	/* If the first link comes up, start the periodical RLMT timeout. */
+	if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
+		Para2.Para32[0] = pRPort->Net->NetNumber;
+		Para2.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
+			pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
+	}
+
+	Para2 = Para;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+		SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
+
+	/* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
+	if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
+		(Para2.pParaPtr =
+			SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
+			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
+		) != NULL) {
+		/* Send "new" packet to RLMT multicast address. */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+	}
+
+	if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
+		if ((Para2.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
+			pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
+			pRPort->Net->CheckingState |=
+				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Event END.\n"))
+}	/* SkRlmtEvtLinkUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortUpTim - PORT_UP_TIM
+ *
+ * Description:
+ *	This routine handles PORT_UP_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortUpTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
+		return;
+	}
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
+		return;
+	}
+
+	pRPort->PortDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_UP;
+	pRPort->Net->PortsUp++;
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (pAC->Rlmt.NumNets <= 1) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Event END.\n"))
+}	/* SkRlmtEvtPortUpTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortDownTim - PORT_DOWN_*
+ *
+ * Description:
+ *	This routine handles PORT_DOWN_* events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortDownX(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
+			Para.Para32[0], Event))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
+		return;
+	}
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+		return;
+	}
+
+	/* Stop port's timers. */
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+	if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+		pRPort->PortState = SK_RLMT_PS_DOWN;
+	}
+
+	if (!pRPort->PortDown) {
+		pRPort->Net->PortsUp--;
+		pRPort->PortDown = SK_TRUE;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
+	}
+
+	pRPort->PacketsPerTimeSlot = 0;
+	/* pRPort->DataPacketsPerTimeSlot = 0; */
+	pRPort->BpduPacketsPerTimeSlot = 0;
+	pRPort->BcTimeStamp = 0;
+
+	/*
+	 * RA;:;: To be checked:
+	 * - actions at RLMT_STOP: We should not switch anymore.
+	 */
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (Para.Para32[0] ==
+			pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
+			/* Active Port went down. */
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+}	/* SkRlmtEvtPortDownX */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkDown - LINK_DOWN
+ *
+ * Description:
+ *	This routine handles LINK_DOWN events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkDown(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		pRPort->Net->LinksUp--;
+		pRPort->LinkDown = SK_TRUE;
+		pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
+
+		if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+		}
+
+		/* Ensure that port is marked down. */
+		Para.Para32[1] = -1;
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Event END.\n"))
+}	/* SkRlmtEvtLinkDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortAddr - PORT_ADDR
+ *
+ * Description:
+ *	This routine handles PORT_ADDR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortAddr(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_U32			i, j;
+	SK_RLMT_PORT	*pRPort;
+	SK_MAC_ADDR		*pOldMacAddr;
+	SK_MAC_ADDR		*pNewMacAddr;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
+		return;
+	}
+
+	/* Port's physical MAC address changed. */
+	pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+	pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+	/*
+	 * NOTE: This is not scalable for solutions where ports are
+	 *	 checked remotely.  There, we need to send an RLMT
+	 *	 address change packet - and how do we ensure delivery?
+	 */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		pRPort = &pAC->Rlmt.Port[i];
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (SK_ADDR_EQUAL(
+				pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
+				pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
+			}
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event END.\n"))
+}	/* SkRlmtEvtPortAddr */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStart - START
+ *
+ * Description:
+ *	This routine handles START events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStart(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortIdx;
+	SK_U32		PortNumber;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets should have been started.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
+		pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
+
+		/* Change PrefPort to internal default. */
+		Para2.Para32[0] = 0xFFFFFFFF;
+		Para2.Para32[1] = Para.Para32[0];
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
+	}
+
+	PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
+	PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
+
+	pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
+
+	/* Start preferred port. */
+	SkRlmtPortStart(pAC, IoC, PortNumber);
+
+	/* Start Timer (for first port only). */
+	Para2.Para32[0] = PortNumber;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
+		SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
+
+	pAC->Rlmt.NetsStarted++;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event END.\n"))
+}	/* SkRlmtEvtStart */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStop - STOP
+ *
+ * Description:
+ *	This routine handles STOP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStop(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortNumber;
+	SK_U32		i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.NetsStarted == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	/* Stop RLMT timers. */
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer);
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
+
+	/* Stop net. */
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
+	pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
+	Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+	Para2.Para32[1] = Para.Para32[0];			/* Net# */
+	SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+	/* Stop ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
+
+			pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
+			Para2.Para32[0] = PortNumber;
+			Para2.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
+		}
+	}
+
+	pAC->Rlmt.NetsStarted--;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Event END.\n"))
+}	/* SkRlmtEvtStop */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtTim - TIM
+ *
+ * Description:
+ *	This routine handles TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_U32			Timeout;
+	SK_U32			NewTimeout;
+	SK_U32			PortNumber;
+	SK_U32			i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_TIM Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event EMPTY.\n"))
+		return;
+	}
+
+	if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
+		pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
+		/* Mode changed or all links down: No more link checking. */
+		return;
+	}
+
+#if 0
+	pAC->Rlmt.SwitchCheckCounter--;
+	if (pAC->Rlmt.SwitchCheckCounter == 0) {
+		pAC->Rlmt.SwitchCheckCounter;
+	}
+#endif	/* 0 */
+
+	NewTimeout = SK_RLMT_DEF_TO_VAL;
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		pRPort = &pAC->Rlmt.Port[PortNumber];
+		if (!pRPort->LinkDown) {
+			Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
+			if (Timeout < NewTimeout) {
+				NewTimeout = Timeout;
+			}
+
+			/*
+			 * These counters should be set to 0 for all ports before the
+			 * first frame is sent in the next loop.
+			 */
+			pRPort->PacketsPerTimeSlot = 0;
+			/* pRPort->DataPacketsPerTimeSlot = 0; */
+			pRPort->BpduPacketsPerTimeSlot = 0;
+		}
+	}
+	pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
+		/*
+		 * If checking remote ports, also send packets if
+		 *   (LinksUp == 1) &&
+		 *   this port checks at least one (remote) port.
+		 */
+
+		/*
+		 * Must be new loop, as SkRlmtCheckPort can request to
+		 * check segmentation when e.g. checking the last port.
+		 */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
+				SkRlmtSend(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
+			}
+		}
+	}
+
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
+		pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
+		Para);
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
+		(pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
+		SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
+			SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
+			SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event END.\n"))
+}	/* SkRlmtEvtTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtSegTim - SEG_TIM
+ *
+ * Description:
+ *	This routine handles SEG_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSegTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+#ifdef xDEBUG
+	int j;
+#endif	/* DEBUG */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SEG_TIM Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event EMPTY.\n"))
+		return;
+	}
+
+#ifdef xDEBUG
+	for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+		SK_ADDR_PORT	*pAPort;
+		SK_U32			k;
+		SK_U16			*InAddr;
+		SK_U8			InAddr8[6];
+
+		InAddr = (SK_U16 *)&InAddr8[0];
+		pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
+		for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
+			/* Get exact match address k from port j. */
+			XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+				XM_EXM(k), InAddr);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+					k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+					InAddr8[0], InAddr8[1], InAddr8[2],
+					InAddr8[3], InAddr8[4], InAddr8[5],
+					pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
+					pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
+					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
+		}
+	}
+#endif	/* xDEBUG */
+
+	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event END.\n"))
+}	/* SkRlmtEvtSegTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPacketRx - PACKET_RECEIVED
+ *
+ * Description:
+ *	This routine handles PACKET_RECEIVED events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPacketRx(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_MBUF *pMb */
+{
+	SK_MBUF	*pMb;
+	SK_MBUF	*pNextMb;
+	SK_U32	NetNumber;
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
+
+	/* Should we ignore frames during port switching? */
+
+#ifdef DEBUG
+	pMb = Para.pParaPtr;
+	if (pMb == NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
+	}
+	else if (pMb->pNext != NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("More than one mbuf or pMb->pNext not set.\n"))
+	}
+#endif	/* DEBUG */
+
+	for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+		pNextMb = pMb->pNext;
+		pMb->pNext = NULL;
+
+		NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
+		if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+		else {
+			SkRlmtPacketReceive(pAC, IoC, pMb);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event END.\n"))
+}	/* SkRlmtEvtPacketRx */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsClear - STATS_CLEAR
+ *
+ * Description:
+ *	This routine handles STATS_CLEAR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsClear(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
+
+	/* Clear statistics for logical and physical ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		pRPort =
+			&pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
+		pRPort->TxHelloCts = 0;
+		pRPort->RxHelloCts = 0;
+		pRPort->TxSpHelloReqCts = 0;
+		pRPort->RxSpHelloCts = 0;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event END.\n"))
+}	/* SkRlmtEvtStatsClear */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsUpdate - STATS_UPDATE
+ *
+ * Description:
+ *	This routine handles STATS_UPDATE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsUpdate(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
+
+	/* Update statistics - currently always up-to-date. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event END.\n"))
+}	/* SkRlmtEvtStatsUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPrefportChange - PREFPORT_CHANGE
+ *
+ * Description:
+ *	This routine handles PREFPORT_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPrefportChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortIndex; SK_U32 NetNumber */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	/* 0xFFFFFFFF == auto-mode. */
+	if (Para.Para32[0] == 0xFFFFFFFF) {
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
+	}
+	else {
+		if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+			return;
+		}
+
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
+	}
+
+	pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
+
+	if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+		SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
+}	/* SkRlmtEvtPrefportChange */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtSetNets - SET_NETS
+ *
+ * Description:
+ *	This routine handles SET_NETS events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSetNets(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NumNets; SK_U32 -1 */
+{
+	int i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
+		Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad number of nets: %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == pAC->Rlmt.NumNets) {	/* No change. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	/* Entering and leaving dual mode only allowed while nets are stopped. */
+	if (pAC->Rlmt.NetsStarted > 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Changing dual mode only allowed while all nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 1) {
+		if (pAC->Rlmt.NumNets > 1) {
+			/* Clear logical MAC addr from second net's active port. */
+			(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+				Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
+			pAC->Rlmt.Net[1].NumPorts = 0;
+		}
+
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to one net with two ports.\n"))
+	}
+	else if (Para.Para32[0] == 2) {
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
+		pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
+		pAC->Rlmt.Net[0].NumPorts =
+			pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
+
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		/* Set logical MAC addr on second net's active port. */
+		(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+			Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to two nets with one port each.\n"))
+	}
+	else {
+		/* Not implemented for more than two nets. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SetNets not implemented for more than two nets.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event END.\n"))
+}	/* SkRlmtSetNets */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtModeChange - MODE_CHANGE
+ *
+ * Description:
+ *	This routine handles MODE_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtModeChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NewMode; SK_U32 NetNumber */
+{
+	SK_EVPARA	Para2;
+	SK_U32		i;
+	SK_U32		PrevRlmtMode;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	Para.Para32[0] |= SK_RLMT_CHECK_LINK;
+
+	if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) &&
+		Para.Para32[0] != SK_RLMT_MODE_CLS) {
+		pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Forced RLMT mode to CLS on single port net.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	/* Update RLMT mode. */
+	PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
+	pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
+
+	if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		/* SK_RLMT_CHECK_LOC_LINK bit changed. */
+		if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
+			pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
+			pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
+			/* 20001207 RA: Was "PortsUp == 1". */
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
+				pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
+				SKGE_RLMT, SK_RLMT_TIM, Para2);
+		}
+	}
+
+	if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
+		/* SK_RLMT_CHECK_SEG bit changed. */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
+			(void)SkAddrMcClear(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				&SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+			if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
+				SK_RLMT_CHECK_SEG) != 0) {
+				/* Add BPDU MC address. */
+				(void)SkAddrMcAdd(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+					&BridgeMcAddr, SK_ADDR_PERMANENT);
+
+				if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+					if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
+						(Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
+						pAC, IoC, i)) != NULL) {
+						pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
+							SK_FALSE;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+					}
+				}
+			}
+			(void)SkAddrMcUpdate(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
+		}	/* for ... */
+
+		if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
+		}
+	}	/* SK_RLMT_CHECK_SEG bit changed. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event END.\n"))
+}	/* SkRlmtEvtModeChange */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ *	This routine calls subroutines to handle PORT- and RLMT-specific events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	0
+ */
+int	SkRlmtEvent(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* Event-specific parameter */
+{
+	switch (Event) {
+
+	/* ----- PORT events ----- */
+
+	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortStartTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_LINK_UP:		/* From SIRQ. */
+		SkRlmtEvtLinkUp(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortUpTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORTDOWN:			/* From RLMT. */
+	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
+	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
+		break;
+	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
+		SkRlmtEvtLinkDown(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
+		SkRlmtEvtPortAddr(pAC, IoC, Para);
+		break;
+
+	/* ----- RLMT events ----- */
+
+	case SK_RLMT_START:		/* From DRV. */
+		SkRlmtEvtStart(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STOP:		/* From DRV. */
+		SkRlmtEvtStop(pAC, IoC, Para);
+		break;
+	case SK_RLMT_TIM:		/* From RLMT via TIME. */
+		SkRlmtEvtTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SEG_TIM:
+		SkRlmtEvtSegTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
+		SkRlmtEvtPacketRx(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
+		SkRlmtEvtStatsClear(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
+		SkRlmtEvtStatsUpdate(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
+		SkRlmtEvtPrefportChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
+		SkRlmtEvtModeChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SET_NETS:	/* From DRV. */
+		SkRlmtEvtSetNets(pAC, IoC, Para);
+		break;
+
+	/* ----- Unknown events ----- */
+
+	default:	/* Create error log entry. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Unknown RLMT Event %d.\n", Event))
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
+		break;
+	}	/* switch() */
+
+	return (0);
+}	/* SkRlmtEvent */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/sktimer.c b/drivers/net/sk98lin/sktimer.c
new file mode 100644
index 0000000..37cd4c9
--- /dev/null
+++ b/drivers/net/sk98lin/sktimer.c
@@ -0,0 +1,297 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1999/11/22 13:38:51 $
+ * Purpose:	High level timer functions.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktimer.c,v $
+ *	Revision 1.12  1999/11/22 13:38:51  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.11  1998/12/17 13:24:13  gklug
+ *	fix: restart problem: do NOT destroy timer queue if init 1 is done
+ *
+ *	Revision 1.10  1998/10/15 15:11:36  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *
+ *	Revision 1.9  1998/09/15 15:15:04  cgoos
+ *	Changed TRUE/FALSE to SK_TRUE/SK_FALSE
+ *
+ *	Revision 1.8  1998/09/08 08:47:55  gklug
+ *	add: init level handling
+ *
+ *	Revision 1.7  1998/08/19 09:50:53  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *
+ *	Revision 1.6  1998/08/17 13:43:13  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *
+ *	Revision 1.5  1998/08/14 07:09:14  gklug
+ *	fix: chg pAc -> pAC
+ *
+ *	Revision 1.4  1998/08/07 12:53:46  gklug
+ *	fix: first compiled version
+ *
+ *	Revision 1.3  1998/08/07 09:31:53  gklug
+ *	fix: delta spelling
+ *
+ *	Revision 1.2  1998/08/07 09:31:02  gklug
+ *	adapt functions to new c coding conventions
+ *	rmv: "fast" handling
+ *	chg: inserting of new timer in queue.
+ *	chg: event queue generation when timer runs out
+ *
+ *	Revision 1.1  1998/08/05 11:27:55  gklug
+ *	first version: adapted from SMT
+ *
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+
+/* Forward declaration */
+static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
+
+
+/*
+ * Inits the software timer
+ *
+ * needs to be called during Init level 1.
+ */
+void	SkTimerInit(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int	Level)		/* Init Level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Tim.StQueue = 0 ;
+		break;
+	case SK_INIT_IO:
+		SkHwtInit(pAC,Ioc) ;
+		SkTimerDone(pAC, Ioc);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Stops a high level timer
+ * - If a timer is not in the queue the function returns normally, too.
+ */
+void	SkTimerStop(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer)	/* Timer Pointer to be started */
+{
+	SK_TIMER	**ppTimPrev ;
+	SK_TIMER	*pTm ;
+
+	/*
+	 * remove timer from queue
+	 */
+	pTimer->TmActive = SK_FALSE ;
+	if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
+		SkHwtStop(pAC,Ioc) ;
+	}
+	for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
+		ppTimPrev = &pTm->TmNext ) {
+		if (pTm == pTimer) {
+			/*
+			 * Timer found in queue
+			 * - dequeue it and
+			 * - correct delta of the next timer
+			 */
+			*ppTimPrev = pTm->TmNext ;
+
+			if (pTm->TmNext) {
+				/* correct delta of next timer in queue */
+				pTm->TmNext->TmDelta += pTm->TmDelta ;
+			}
+			return ;
+		}
+	}
+}
+
+/*
+ * Start a high level software timer
+ */
+void	SkTimerStart(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer,	/* Timer Pointer to be started */
+SK_U32		Time,		/* Time value */
+SK_U32		Class,		/* Event Class for this timer */
+SK_U32		Event,		/* Event Value for this timer */
+SK_EVPARA	Para)		/* Event Parameter for this timer */
+{
+	SK_TIMER	**ppTimPrev ;
+	SK_TIMER	*pTm ;
+	SK_U32		Delta ;
+
+	Time /= 16 ;		/* input is uS, clock ticks are 16uS */
+	if (!Time)
+		Time = 1 ;
+
+	SkTimerStop(pAC,Ioc,pTimer) ;
+
+	pTimer->TmClass = Class ;
+	pTimer->TmEvent = Event ;
+	pTimer->TmPara = Para ;
+	pTimer->TmActive = SK_TRUE ;
+
+	if (!pAC->Tim.StQueue) {
+		/* First Timer to be started */
+		pAC->Tim.StQueue = pTimer ;
+		pTimer->TmNext = 0 ;
+		pTimer->TmDelta = Time ;
+		SkHwtStart(pAC,Ioc,Time) ;
+		return ;
+	}
+
+	/*
+	 * timer correction
+	 */
+	timer_done(pAC,Ioc,0) ;
+
+	/*
+	 * find position in queue
+	 */
+	Delta = 0 ;
+	for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
+		ppTimPrev = &pTm->TmNext ) {
+		if (Delta + pTm->TmDelta > Time) {
+			/* Position found */
+			/* Here the timer needs to be inserted. */
+			break ;
+		}
+		Delta += pTm->TmDelta ;
+	}
+
+	/* insert in queue */
+	*ppTimPrev = pTimer ;
+	pTimer->TmNext = pTm ;
+	pTimer->TmDelta = Time - Delta ;
+
+	if (pTm) {
+		/* There is a next timer
+		 * -> correct its Delta value.
+		 */
+		pTm->TmDelta -= pTimer->TmDelta ;
+	}
+
+	/*
+	 * start new with first
+	 */
+	SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
+}
+
+
+void	SkTimerDone(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc)		/* IoContext */
+{
+	timer_done(pAC,Ioc,1) ;
+}
+
+
+static void	timer_done(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int	Restart)	/* Do we need to restart the Hardware timer ? */
+{
+	SK_U32		Delta ;
+	SK_TIMER	*pTm ;
+	SK_TIMER	*pTComp ;	/* Timer completed now now */
+	SK_TIMER	**ppLast ;	/* Next field of Last timer to be deq */
+	int		Done = 0 ;
+
+	Delta = SkHwtRead(pAC,Ioc) ;
+	ppLast = &pAC->Tim.StQueue ;
+	pTm = pAC->Tim.StQueue ;
+	while (pTm && !Done) {
+		if (Delta >= pTm->TmDelta) {
+			/* Timer ran out */
+			pTm->TmActive = SK_FALSE ;
+			Delta -= pTm->TmDelta ;
+			ppLast = &pTm->TmNext ;
+			pTm = pTm->TmNext ;
+		} else {
+			/* We found the first timer that did not run out */
+			pTm->TmDelta -= Delta ;
+			Delta = 0 ;
+			Done = 1 ;
+		}
+	}
+	*ppLast = 0 ;
+	/*
+	 * pTm points to the first Timer that did not run out.
+	 * StQueue points to the first Timer that run out.
+	 */
+
+	for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) {
+		SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent,
+			pTComp->TmPara) ;
+	}
+
+	/* Set head of timer queue to the first timer that did not run out */
+	pAC->Tim.StQueue = pTm ;
+
+	if (Restart && pAC->Tim.StQueue) {
+		/* Restart HW timer */
+		SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
+	}
+}
+
+#endif /* CONFIG_SK98 */
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
new file mode 100644
index 0000000..3b81e67
--- /dev/null
+++ b/drivers/net/sk98lin/skvpd.c
@@ -0,0 +1,1329 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.37 $
+ * Date:	$Date: 2003/01/13 10:42:45 $
+ * Purpose:	Shared software to read and write VPD data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skvpd.c,v $
+ *	Revision 1.37  2003/01/13 10:42:45  rschmidt
+ *	Replaced check for PCI device Id from YUKON with GENESIS
+ *	to set the VPD size in VpdInit()
+ *	Editorial changes
+ *
+ *	Revision 1.36  2002/11/14 15:16:56  gheinig
+ *	Added const specifier to key and buf parameters for VpdPara, VpdRead
+ *	and VpdWrite for Diag 7 GUI
+ *
+ *	Revision 1.35  2002/10/21 14:31:59  gheinig
+ *	Took out CVS web garbage at head of file
+ *
+ *	Revision 1.34  2002/10/21 11:47:24  gheinig
+ *	Reverted to version 1.32 due to unwanted commit
+ *
+ *	Revision 1.32  2002/10/14 16:04:29  rschmidt
+ *	Added saving of VPD ROM Size from PCI_OUR_REG_2
+ *	Avoid reading of PCI_OUR_REG_2 in VpdTransferBlock()
+ *	Editorial changes
+ *
+ *	Revision 1.31  2002/09/10 09:21:32  mkarl
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis
+ *
+ *	Revision 1.30  2002/09/09 14:43:03  mkarl
+ *	changes for diagnostics in order to read VPD data before the adapter
+ *	has been initialized
+ *	editorial changes
+ *
+ *	Revision 1.29  2002/07/26 13:20:43  mkarl
+ *	added Yukon support
+ *	save size of VPD in pAC->vpd.vpd_size
+ *
+ *	Revision 1.28  2002/04/02 15:31:47  afischer
+ *	Bug fix in VpdWait()
+ *
+ *	Revision 1.27  2000/08/10 11:29:06  rassmann
+ *	Editorial changes.
+ *	Preserving 32-bit alignment in structs for the adapter context.
+ *	Removed unused function VpdWriteDword() (#if 0).
+ *	Made VpdReadKeyword() available for SKDIAG only.
+ *
+ *	Revision 1.26  2000/06/13 08:00:01  mkarl
+ *	additional cast to avoid compile problems in 64 bit environment
+ *
+ *	Revision 1.25  1999/11/22 13:39:32  cgoos
+ *	Changed license header to GPL.
+ *
+ *	Revision 1.24  1999/03/11 14:25:49  malthoff
+ *	Replace __STDC__ with SK_KR_PROTO.
+ *
+ *	Revision 1.23  1999/01/11 15:13:11  gklug
+ *	fix: syntax error
+ *
+ *	Revision 1.22  1998/10/30 06:41:15  gklug
+ *	rmv: WARNING
+ *
+ *	Revision 1.21  1998/10/29 07:15:14  gklug
+ *	fix: Write Stream function needs verify.
+ *
+ *	Revision 1.20  1998/10/28 18:05:08  gklug
+ *	chg: no DEBUG in VpdMayWrite
+ *
+ *	Revision 1.19  1998/10/28 15:56:11  gklug
+ *	fix: Return len at end of ReadStream
+ *	fix: Write even less than 4 bytes correctly
+ *
+ *	Revision 1.18  1998/10/28 09:00:47  gklug
+ *	fix: unreferenced local vars
+ *
+ *	Revision 1.17  1998/10/28 08:25:45  gklug
+ *	fix: WARNING
+ *
+ *	Revision 1.16  1998/10/28 08:17:30  gklug
+ *	fix: typo
+ *
+ *	Revision 1.15  1998/10/28 07:50:32  gklug
+ *	fix: typo
+ *
+ *	Revision 1.14  1998/10/28 07:20:38  gklug
+ *	chg: Interface functions to use IoC as parameter as well
+ *	fix: VpdRead/WriteDWord now returns SK_U32
+ *	chg: VPD_IN/OUT names conform to SK_IN/OUT
+ *	add: usage of VPD_IN/OUT8 macros
+ *	add: VpdRead/Write Stream functions to r/w a stream of data
+ *	fix: VpdTransferBlock swapped illegal
+ *	add: VpdMayWrite
+ *
+ *	Revision 1.13  1998/10/22 10:02:37  gklug
+ *	fix: SysKonnectFileId typo
+ *
+ *	Revision 1.12  1998/10/20 10:01:01  gklug
+ *	fix: parameter to SkOsGetTime
+ *
+ *	Revision 1.11  1998/10/15 12:51:48  malthoff
+ *	Remove unrequired parameter p in vpd_setup_para().
+ *
+ *	Revision 1.10  1998/10/08 14:52:43  malthoff
+ *	Remove CvsId by SysKonnectFileId.
+ *
+ *	Revision 1.9  1998/09/16 07:33:52  malthoff
+ *	replace memcmp() by SK_MEMCMP and
+ *	memcpy() by SK_MEMCPY() to be
+ *	independent from the 'C' Standard Library.
+ *
+ *	Revision 1.8  1998/08/19 12:52:35  malthoff
+ *	compiler fix: use SK_VPD_KEY instead of S_VPD.
+ *
+ *	Revision 1.7  1998/08/19 08:14:01  gklug
+ *	fix: remove struct keyword as much as possible from the C-code (see CCC)
+ *
+ *	Revision 1.6  1998/08/18 13:03:58  gklug
+ *	SkOsGetTime now returns SK_U64
+ *
+ *	Revision 1.5  1998/08/18 08:17:29  malthoff
+ *	Ensure we issue a VPD read in vpd_read_dword().
+ *	Discard all VPD keywords other than Vx or Yx, where
+ *	x is '0..9' or 'A..Z'.
+ *
+ *	Revision 1.4  1998/07/03 14:52:19  malthoff
+ *	Add category SK_DBGCAT_FATAL to some debug macros.
+ *	bug fix: correct the keyword name check in vpd_write().
+ *
+ *	Revision 1.3  1998/06/26 11:16:53  malthoff
+ *	Correct the modified File Identifier.
+ *
+ *	Revision 1.2  1998/06/26 11:13:43  malthoff
+ *	Modify the File Identifier.
+ *
+ *	Revision 1.1  1998/06/19 14:11:08  malthoff
+ *	Created, Tests with AIX were performed successfully
+ *
+ *
+ ******************************************************************************/
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+/*
+	Please refer skvpd.txt for infomation how to include this module
+ */
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/skdebug.h"
+#include "h/skdrv2nd.h"
+
+/*
+ * Static functions
+ */
+#ifndef SK_KR_PROTO
+static SK_VPD_PARA	*vpd_find_para(
+	SK_AC	*pAC,
+	const char	*key,
+	SK_VPD_PARA *p);
+#else	/* SK_KR_PROTO */
+static SK_VPD_PARA	*vpd_find_para();
+#endif	/* SK_KR_PROTO */
+
+/*
+ * waits for a completion of a VPD transfer
+ * The VPD transfer must complete within SK_TICKS_PER_SEC/16
+ *
+ * returns	0:	success, transfer completes
+ *		error	exit(9) with a error message
+ */
+static int VpdWait(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+int		event)	/* event to wait for (VPD_READ / VPD_write) completion*/
+{
+	SK_U64	start_time;
+	SK_U16	state;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD wait for %s\n", event?"Write":"Read"));
+	start_time = SkOsGetTime(pAC);
+	do {
+		if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) {
+
+			/* Bug fix AF: Thu Mar 28 2002
+			 * Do not call: VPD_STOP(pAC, IoC);
+			 * A pending VPD read cycle can not be aborted by writing
+			 * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
+			 * Although the write threshold in the OUR-register protects
+			 * VPD read only space from being overwritten this does not
+			 * protect a VPD read from being `converted` into a VPD write
+			 * operation (on the fly). As a consequence the VPD_STOP would
+			 * delete VPD read only data. In case of any problems with the
+			 * I2C bus we exit the loop here. The I2C read operation can
+			 * not be aborted except by a reset (->LR).
+			 */
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
+				("ERROR:VPD wait timeout\n"));
+			return(1);
+		}
+
+		VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("state = %x, event %x\n",state,event));
+	} while((int)(state & PCI_VPD_FLAG) == event);
+
+	return(0);
+}
+
+#ifdef SKDIAG
+
+/*
+ * Read the dword at address 'addr' from the VPD EEPROM.
+ *
+ * Needed Time:	MIN 1,3 ms	MAX 2,6 ms
+ *
+ * Note: The DWord is returned in the endianess of the machine the routine
+ *       is running on.
+ *
+ * Returns the data read.
+ */
+SK_U32 VpdReadDWord(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+int		addr)	/* VPD address */
+{
+	SK_U32	Rtv;
+
+	/* start VPD read */
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD read dword at 0x%x\n",addr));
+	addr &= ~VPD_WRITE;		/* ensure the R/W bit is set to read */
+
+	VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr);
+
+	/* ignore return code here */
+	(void)VpdWait(pAC, IoC, VPD_READ);
+
+	/* Don't swap here, it's a data stream of bytes */
+	Rtv = 0;
+
+	VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD read dword data = 0x%x\n",Rtv));
+	return(Rtv);
+}
+
+#endif	/* SKDIAG */
+
+#if 0
+
+/*
+	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
+	verify that the data is written.
+
+ Needed Time:
+
+.				MIN		MAX
+. -------------------------------------------------------------------
+. write				1.8 ms		3.6 ms
+. internal write cyles		0.7 ms		7.0 ms
+. -------------------------------------------------------------------
+. over all program time	 	2.5 ms		10.6 ms
+. read				1.3 ms		2.6 ms
+. -------------------------------------------------------------------
+. over all 			3.8 ms		13.2 ms
+.
+
+
+ Returns	0:	success
+			1:	error,	I2C transfer does not terminate
+			2:	error,	data verify error
+
+ */
+static int VpdWriteDWord(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+int		addr,	/* VPD address */
+SK_U32	data)	/* VPD data to write */
+{
+	/* start VPD write */
+	/* Don't swap here, it's a data stream of bytes */
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD write dword at addr 0x%x, data = 0x%x\n",addr,data));
+	VPD_OUT32(pAC, IoC, PCI_VPD_DAT_REG, (SK_U32)data);
+	/* But do it here */
+	addr |= VPD_WRITE;
+
+	VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE));
+
+	/* this may take up to 10,6 ms */
+	if (VpdWait(pAC, IoC, VPD_WRITE)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Write Timed Out\n"));
+		return(1);
+	};
+
+	/* verify data */
+	if (VpdReadDWord(pAC, IoC, addr) != data) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Data Verify Error\n"));
+		return(2);
+	}
+	return(0);
+}	/* VpdWriteDWord */
+
+#endif	/* 0 */
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdWriteStream(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i;
+	int		j;
+	SK_U16	AdrReg;
+	int		Rtv;
+	SK_U8	* pComp;	/* Compare pointer */
+	SK_U8	Data;		/* Input Data for Compare */
+
+	/* Init Compare Pointer */
+	pComp = (SK_U8 *) buf;
+
+	for (i = 0; i < Len; i++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/*
+			 * At the begin of each cycle read the Data Reg
+			 * So it is initialized even if only a few bytes
+			 * are written.
+			 */
+			AdrReg = (SK_U16) Addr;
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				return(i);
+			}
+		}
+
+		/* Write current Byte */
+		VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+				*(SK_U8*)buf);
+
+		if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr;
+			Addr += sizeof(SK_U32);
+			AdrReg |= VPD_WRITE;	/* WRITE operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_WRITE);
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("Write Timed Out\n"));
+				return(i - (i%sizeof(SK_U32)));
+			}
+
+			/*
+			 * Now re-read to verify
+			 */
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("Verify Timed Out\n"));
+				return(i - (i%sizeof(SK_U32)));
+			}
+
+			for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) {
+
+				VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data);
+
+				if (Data != *pComp) {
+					/* Verify Error */
+					SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+						("WriteStream Verify Error\n"));
+					return(i - (i%sizeof(SK_U32)) + j);
+				}
+			}
+		}
+	}
+
+	return(Len);
+}
+
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdReadStream(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i;
+	SK_U16	AdrReg;
+	int		Rtv;
+
+	for (i = 0; i < Len; i++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr;
+			Addr += sizeof(SK_U32);
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				return(i);
+			}
+		}
+		VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+			(SK_U8 *)buf);
+	}
+
+	return(Len);
+}
+
+/*
+ *	Read ore writes 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdTransferBlock(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		addr,	/* VPD start address */
+int		len,	/* number of bytes to read / to write */
+int		dir)	/* transfer direction may be VPD_READ or VPD_WRITE */
+{
+	int		Rtv;	/* Return value */
+	int		vpd_rom_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD %s block, addr = 0x%x, len = %d\n",
+		dir ? "write" : "read", addr, len));
+
+	if (len == 0)
+		return(0);
+
+	vpd_rom_size = pAC->vpd.rom_size;
+
+	if (addr > vpd_rom_size - 4) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Address error: 0x%x, exp. < 0x%x\n",
+			addr, vpd_rom_size - 4));
+		return(0);
+	}
+
+	if (addr + len > vpd_rom_size) {
+		len = vpd_rom_size - addr;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Warning: len was cut to %d\n", len));
+	}
+
+	if (dir == VPD_READ) {
+		Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
+	}
+	else {
+		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
+	}
+
+	return(Rtv);
+}
+
+#ifdef SKDIAG
+
+/*
+ *	Read 'len' bytes of VPD data, starting at 'addr'.
+ *
+ * Returns number of bytes read.
+ */
+int VpdReadBlock(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer were the data should be stored */
+int		addr,	/* start reading at the VPD address */
+int		len)	/* number of bytes to read */
+{
+	return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ));
+}
+
+/*
+ *	Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
+ *
+ * Returns number of bytes writes.
+ */
+int VpdWriteBlock(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer, holds the data to write */
+int		addr,	/* start writing at the VPD address */
+int		len)	/* number of bytes to write */
+{
+	return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE));
+}
+#endif	/* SKDIAG */
+
+/*
+ * (re)initialize the VPD buffer
+ *
+ * Reads the VPD data from the EEPROM into the VPD buffer.
+ * Get the remaining read only and read / write space.
+ *
+ * return	0:	success
+ *		1:	fatal VPD error
+ */
+static int VpdInit(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	SK_VPD_PARA *r, rp;	/* RW or RV */
+	int		i;
+	unsigned char	x;
+	int		vpd_size;
+	SK_U16	dev_id;
+	SK_U32	our_reg2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. "));
+
+	VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &dev_id);
+
+	VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2);
+
+	pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+
+	/*
+	 * this function might get used before the hardware is initialized
+	 * therefore we cannot always trust in GIChipId
+	 */
+	if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 &&
+		dev_id != VPD_DEV_ID_GENESIS) ||
+		((pAC->vpd.v.vpd_status & VPD_VALID) != 0 &&
+		!pAC->GIni.GIGenesis)) {
+
+		/* for Yukon the VPD size is always 256 */
+		vpd_size = VPD_SIZE_YUKON;
+	}
+	else {
+		/* Genesis uses the maximum ROM size up to 512 for VPD */
+		if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) {
+			vpd_size = VPD_SIZE_GENESIS;
+		}
+		else {
+			vpd_size = pAC->vpd.rom_size;
+		}
+	}
+
+	/* read the VPD data into the VPD buffer */
+	if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf, 0, vpd_size, VPD_READ)
+		!= vpd_size) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Block Read Error\n"));
+		return(1);
+	}
+
+	pAC->vpd.vpd_size = vpd_size;
+
+	/* find the end tag of the RO area */
+	if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n"));
+		return(1);
+	}
+
+	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n"));
+		return(1);
+	}
+	pAC->vpd.v.vpd_free_ro = r->p_len - 1;
+
+	/* test the checksum */
+	for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) {
+		x += pAC->vpd.vpd_buf[i];
+	}
+
+	if (x != 0) {
+		/* checksum error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("VPD Checksum Error\n"));
+		return(1);
+	}
+
+	/* find and check the end tag of the RW area */
+	if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n"));
+		return(1);
+	}
+
+	if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n"));
+		return(1);
+	}
+	pAC->vpd.v.vpd_free_rw = r->p_len;
+
+	/* everything seems to be ok */
+	if (pAC->GIni.GIChipId != 0) {
+		pAC->vpd.v.vpd_status |= VPD_VALID;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT,
+		("done. Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+	return(0);
+}
+
+/*
+ *	find the Keyword 'key' in the VPD buffer and fills the
+ *	parameter struct 'p' with it's values
+ *
+ * returns	*p	success
+ *		0:	parameter was not found or VPD encoding error
+ */
+static SK_VPD_PARA *vpd_find_para(
+SK_AC		*pAC,	/* common data base */
+const char	*key,	/* keyword to find (e.g. "MN") */
+SK_VPD_PARA *p)		/* parameter description struct */
+{
+	char *v	;	/* points to VPD buffer */
+	int max;	/* Maximum Number of Iterations */
+
+	v = pAC->vpd.vpd_buf;
+	max = 128;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD find para %s .. ",key));
+
+	/* check mandatory resource type ID string (Product Name) */
+	if (*v != (char)RES_ID) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Error: 0x%x missing\n", RES_ID));
+		return(0);
+	}
+
+	if (strcmp(key, VPD_NAME) == 0) {
+		p->p_len = VPD_GET_RES_LEN(v);
+		p->p_val = VPD_GET_VAL(v);
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("found, len = %d\n", p->p_len));
+		return(p);
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3;
+	for (;; ) {
+		if (SK_MEMCMP(key,v,2) == 0) {
+			p->p_len = VPD_GET_VPD_LEN(v);
+			p->p_val = VPD_GET_VAL(v);
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("found, len = %d\n",p->p_len));
+			return(p);
+		}
+
+		/* exit when reaching the "RW" Tag or the maximum of itera. */
+		max--;
+		if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
+			break;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
+		}
+		else {
+			v += 3 + VPD_GET_VPD_LEN(v);
+		}
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
+	}
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n"));
+	if (max == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Key/Len Encoding error\n"));
+	}
+#endif /* DEBUG */
+	return(0);
+}
+
+/*
+ *	Move 'n' bytes. Begin with the last byte if 'n' is > 0,
+ *	Start with the last byte if n is < 0.
+ *
+ * returns nothing
+ */
+static void vpd_move_para(
+char	*start,		/* start of memory block */
+char	*end,		/* end of memory block to move */
+int		n)			/* number of bytes the memory block has to be moved */
+{
+	char *p;
+	int i;		/* number of byte copied */
+
+	if (n == 0)
+		return;
+
+	i = (int) (end - start + 1);
+	if (n < 0) {
+		p = start + n;
+		while (i != 0) {
+			*p++ = *start++;
+			i--;
+		}
+	}
+	else {
+		p = end + n;
+		while (i != 0) {
+			*p-- = *end--;
+			i--;
+		}
+	}
+}
+
+/*
+ *	setup the VPD keyword 'key' at 'ip'.
+ *
+ * returns nothing
+ */
+static void vpd_insert_key(
+const char	*key,	/* keyword to insert */
+const char	*buf,	/* buffer with the keyword value */
+int		len,		/* length of the value string */
+char	*ip)		/* inseration point */
+{
+	SK_VPD_KEY *p;
+
+	p = (SK_VPD_KEY *) ip;
+	p->p_key[0] = key[0];
+	p->p_key[1] = key[1];
+	p->p_len = (unsigned char) len;
+	SK_MEMCPY(&p->p_val,buf,len);
+}
+
+/*
+ *	Setup the VPD end tag "RV" / "RW".
+ *	Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
+ *
+ * returns	0:	success
+ *		1:	encoding error
+ */
+static int vpd_mod_endtag(
+SK_AC	*pAC,		/* common data base */
+char	*etp)		/* end pointer input position */
+{
+	SK_VPD_KEY *p;
+	unsigned char	x;
+	int	i;
+	int	vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	p = (SK_VPD_KEY *) etp;
+
+	if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
+		/* something wrong here, encoding error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: invalid end tag\n"));
+		return(1);
+	}
+	if (etp > pAC->vpd.vpd_buf + vpd_size/2) {
+		/* create "RW" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1);
+		pAC->vpd.v.vpd_free_rw = (int) p->p_len;
+		i = pAC->vpd.v.vpd_free_rw;
+		etp += 3;
+	}
+	else {
+		/* create "RV" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3);
+		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
+
+		/* setup checksum */
+		for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) {
+			x += pAC->vpd.vpd_buf[i];
+		}
+		p->p_val = (char) 0 - x;
+		i = pAC->vpd.v.vpd_free_ro;
+		etp += 4;
+	}
+	while (i) {
+		*etp++ = 0x00;
+		i--;
+	}
+
+	return(0);
+}
+
+/*
+ *	Insert a VPD keyword into the VPD buffer.
+ *
+ *	The keyword 'key' is inserted at the position 'ip' in the
+ *	VPD buffer.
+ *	The keywords behind the input position will
+ *	be moved. The VPD end tag "RV" or "RW" is generated again.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		4:	VPD full, keyword was not written
+ *		6:	fatal VPD error
+ *
+ */
+int	VpdSetupPara(
+SK_AC	*pAC,		/* common data base */
+const char	*key,	/* keyword to insert */
+const char	*buf,	/* buffer with the keyword value */
+int		len,		/* length of the keyword value */
+int		type,		/* VPD_RO_KEY or VPD_RW_KEY */
+int		op)			/* operation to do: ADD_KEY or OWR_KEY */
+{
+	SK_VPD_PARA vp;
+	char	*etp;		/* end tag position */
+	int	free;		/* remaining space in selected area */
+	char	*ip;		/* input position inside the VPD buffer */
+	int	rtv;		/* return code */
+	int	head;		/* additional haeder bytes to move */
+	int	found;		/* additinoal bytes if the keyword was found */
+	int vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD setup para key = %s, val = %s\n",key,buf));
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	rtv = 0;
+	ip = 0;
+	if (type == VPD_RW_KEY) {
+		/* end tag is "RW" */
+		free = pAC->vpd.v.vpd_free_rw;
+		etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3);
+	}
+	else {
+		/* end tag is "RV" */
+		free = pAC->vpd.v.vpd_free_ro;
+		etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4);
+	}
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+	head = 0;
+	found = 0;
+	if (op == OWR_KEY) {
+		if (vpd_find_para(pAC, key, &vp)) {
+			found = 3;
+			ip = vp.p_val - 3;
+			free += vp.p_len + 3;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("Overwrite Key\n"));
+		}
+		else {
+			op = ADD_KEY;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("Add Key\n"));
+		}
+	}
+	if (op == ADD_KEY) {
+		ip = etp;
+		vp.p_len = 0;
+		head = 3;
+	}
+
+	if (len + 3 > free) {
+		if (free < 7) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD Buffer Overflow, keyword not written\n"));
+			return(4);
+		}
+		/* cut it again */
+		len = free - 3;
+		rtv = 2;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD Buffer Full, Keyword was cut\n"));
+	}
+
+	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
+	vpd_insert_key(key, buf, len, ip);
+	if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
+		pAC->vpd.v.vpd_status &= ~VPD_VALID;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD Encoding Error\n"));
+		return(6);
+	}
+
+	return(rtv);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done.
+ *
+ * return:	A pointer to the vpd_status structure. The structure contains
+ *		this fields.
+ */
+SK_VPD_STATUS *VpdStat(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		(void)VpdInit(pAC, IoC);
+	}
+	return(&pAC->vpd.v);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done.
+ *	Scan the VPD buffer for VPD keywords and create the VPD
+ *	keyword list by copying the keywords to 'buf', all after
+ *	each other and terminated with a '\0'.
+ *
+ * Exceptions:	o The Resource Type ID String (product name) is called "Name"
+ *		o The VPD end tags 'RV' and 'RW' are not listed
+ *
+ *	The number of copied keywords is counted in 'elements'.
+ *
+ * returns	0:	success
+ *		2:	buffer overfull, one or more keywords are missing
+ *		6:	fatal VPD error
+ *
+ *	example values after returning:
+ *
+ *		buf =	"Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
+ *		*len =		30
+ *		*elements =	 9
+ */
+int VpdKeys(
+SK_AC	*pAC,		/* common data base */
+SK_IOC	IoC,		/* IO Context */
+char	*buf,		/* buffer where to copy the keywords */
+int		*len,		/* buffer length */
+int		*elements)	/* number of keywords returned */
+{
+	char *v;
+	int n;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. "));
+	*elements = 0;
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD Init Error, terminated\n"));
+			return(6);
+		}
+	}
+
+	if ((signed)strlen(VPD_NAME) + 1 <= *len) {
+		v = pAC->vpd.vpd_buf;
+		strcpy(buf,VPD_NAME);
+		n = strlen(VPD_NAME) + 1;
+		buf += n;
+		*elements = 1;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+			("'%c%c' ",v[0],v[1]));
+	}
+	else {
+		*len = 0;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("buffer overflow\n"));
+		return(2);
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3;
+	for (;; ) {
+		/* exit when reaching the "RW" Tag */
+		if (SK_MEMCMP(VPD_RW,v,2) == 0) {
+			break;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
+			continue;
+		}
+
+		if (n+3 <= *len) {
+			SK_MEMCPY(buf,v,2);
+			buf += 2;
+			*buf++ = '\0';
+			n += 3;
+			v += 3 + VPD_GET_VPD_LEN(v);
+			*elements += 1;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+				("'%c%c' ",v[0],v[1]));
+		}
+		else {
+			*len = n;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("buffer overflow\n"));
+			return(2);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n"));
+	*len = n;
+	return(0);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Search for the VPD keyword
+ *	'key' and copy its value to 'buf'. Add a terminating '\0'.
+ *	If the value does not fit into the buffer cut it after
+ *	'len' - 1 bytes.
+ *
+ * returns	0:	success
+ *		1:	keyword not found
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		6:	fatal VPD error
+ */
+int VpdRead(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+const char	*key,	/* keyword to read (e.g. "MN") */
+char		*buf,	/* buffer where to copy the keyword value */
+int			*len)	/* buffer length */
+{
+	SK_VPD_PARA *p, vp;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+		if (p->p_len > (*(unsigned *)len)-1) {
+			p->p_len = *len - 1;
+		}
+		SK_MEMCPY(buf, p->p_val, p->p_len);
+		buf[p->p_len] = '\0';
+		*len = p->p_len;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+			("%c%c%c%c.., len = %d\n",
+			buf[0],buf[1],buf[2],buf[3],*len));
+	}
+	else {
+		*len = 0;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
+		return(1);
+	}
+	return(0);
+}
+
+
+/*
+ *	Check whether a given key may be written
+ *
+ * returns
+ *	SK_TRUE		Yes it may be written
+ *	SK_FALSE	No it may be written
+ */
+SK_BOOL VpdMayWrite(
+char	*key)	/* keyword to write (allowed values "Yx", "Vx") */
+{
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		return(SK_FALSE);
+	}
+	return(SK_TRUE);
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done. Insert/overwrite the keyword 'key'
+ *	in the VPD buffer. Cut the keyword value if it does not fit
+ *	into the VPD read / write area.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		4:	VPD full, keyword was not written
+ *		5:	keyword cannot be written
+ *		6:	fatal VPD error
+ */
+int VpdWrite(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+const char	*key,	/* keyword to write (allowed values "Yx", "Vx") */
+const char	*buf)	/* buffer where the keyword value can be read from */
+{
+	int len;		/* length of the keyword to write */
+	int rtv;		/* return code */
+	int rtv2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+		("VPD write %s = %s\n",key,buf));
+
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("illegal key tag, keyword not written\n"));
+		return(5);
+	}
+
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	rtv = 0;
+	len = strlen(buf);
+	if (len > VPD_MAX_LEN) {
+		/* cut it */
+		len = VPD_MAX_LEN;
+		rtv = 2;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("keyword too long, cut after %d bytes\n",VPD_MAX_LEN));
+	}
+	if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD write error\n"));
+		return(rtv2);
+	}
+
+	return(rtv);
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Remove the VPD keyword
+ *	'key' from the VPD buffer.
+ *	Only the keywords in the read/write area can be deleted.
+ *	Keywords in the read only area cannot be deleted.
+ *
+ * returns	0:	success, keyword was removed
+ *		1:	keyword not found
+ *		5:	keyword cannot be deleted
+ *		6:	fatal VPD error
+ */
+int VpdDelete(
+SK_AC	*pAC,	/* common data base */
+SK_IOC	IoC,	/* IO Context */
+char	*key)	/* keyword to read (e.g. "MN") */
+{
+	SK_VPD_PARA *p, vp;
+	char *etp;
+	int	vpd_size;
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+		if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+			/* try to delete read only keyword */
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("cannot delete RO keyword\n"));
+			return(5);
+		}
+
+		etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3);
+
+		vpd_move_para(vp.p_val+vp.p_len, etp+2,
+			- ((int)(vp.p_len + 3)));
+		if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
+			pAC->vpd.v.vpd_status &= ~VPD_VALID;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD encoding error\n"));
+			return(6);
+		}
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("keyword not found\n"));
+		return(1);
+	}
+
+	return(0);
+}
+
+/*
+ *	If the VPD buffer contains valid data write the VPD
+ *	read/write area back to the VPD EEPROM.
+ *
+ * returns	0:	success
+ *		3:	VPD transfer timeout
+ */
+int VpdUpdate(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	int vpd_size;
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. "));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) {
+		if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2,
+			vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("transfer timed out\n"));
+			return(3);
+		}
+	}
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n"));
+	return(0);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD buffer
+ *	if not already done. If the keyword "VF" is not present it will be
+ *	created and the error log message will be stored to this keyword.
+ *	If "VF" is not present the error log message will be stored to the
+ *	keyword "VL". "VL" will created or overwritten if "VF" is present.
+ *	The VPD read/write area is saved to the VPD EEPROM.
+ *
+ * returns nothing, errors will be ignored.
+ */
+void VpdErrLog(
+SK_AC	*pAC,	/* common data base */
+SK_IOC	IoC,	/* IO Context */
+char	*msg)	/* error log message */
+{
+	SK_VPD_PARA *v, vf;	/* VF */
+	int len;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+		("VPD error log msg %s\n", msg));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return;
+		}
+	}
+
+	len = strlen(msg);
+	if (len > VPD_MAX_LEN) {
+		/* cut it */
+		len = VPD_MAX_LEN;
+	}
+	if ((v = vpd_find_para(pAC, VPD_VF, &vf)) != NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("overwrite VL\n"));
+		(void)VpdSetupPara(pAC, VPD_VL, msg, len, VPD_RW_KEY, OWR_KEY);
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("write VF\n"));
+		(void)VpdSetupPara(pAC, VPD_VF, msg, len, VPD_RW_KEY, ADD_KEY);
+	}
+
+	(void)VpdUpdate(pAC, IoC);
+}
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c
new file mode 100644
index 0000000..e6b5a95
--- /dev/null
+++ b/drivers/net/sk98lin/skxmac2.c
@@ -0,0 +1,4396 @@
+/******************************************************************************
+ *
+ * Name:	skxmac2.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.91 $
+ * Date:	$Date: 2003/02/05 15:09:34 $
+ * Purpose:	Contains functions to initialize the MACs and PHYs
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skxmac2.c,v $
+ *	Revision 1.91  2003/02/05 15:09:34  rschmidt
+ *	Removed setting of 'Collision Test'-bit in SkGmInitPhyMarv().
+ *	Disabled auto-update for speed, duplex and flow-control when
+ *	auto-negotiation is not enabled (Bug Id #10766).
+ *	Editorial changes.
+ *
+ *	Revision 1.90  2003/01/29 13:35:19  rschmidt
+ *	Increment Rx FIFO Overflow counter only in DEBUG-mode.
+ *	Corrected define for blinking active LED.
+ *
+ *	Revision 1.89  2003/01/28 16:37:45  rschmidt
+ *	Changed init for blinking active LED
+ *
+ *	Revision 1.88  2003/01/28 10:09:38  rschmidt
+ *	Added debug outputs in SkGmInitMac().
+ *	Added customized init of LED registers in SkGmInitPhyMarv(),
+ *	for blinking active LED (#ifdef ACT_LED_BLINK) and
+ *	for normal duplex LED (#ifdef DUP_LED_NORMAL).
+ *	Editorial changes.
+ *
+ *	Revision 1.87  2002/12/10 14:39:05  rschmidt
+ *	Improved initialization of GPHY in SkGmInitPhyMarv().
+ *	Editorial changes.
+ *
+ *	Revision 1.86  2002/12/09 15:01:12  rschmidt
+ *	Added setup of Ext. PHY Specific Ctrl Reg (downshift feature).
+ *
+ *	Revision 1.85  2002/12/05 14:09:16  rschmidt
+ *	Improved avoiding endless loop in SkGmPhyWrite(), SkGmPhyWrite().
+ *	Added additional advertising for 10Base-T when 100Base-T is selected.
+ *	Added case SK_PHY_MARV_FIBER for YUKON Fiber adapter.
+ *	Editorial changes.
+ *
+ *	Revision 1.84  2002/11/15 12:50:09  rschmidt
+ *	Changed SkGmCableDiagStatus() when getting results.
+ *
+ *	Revision 1.83  2002/11/13 10:28:29  rschmidt
+ *	Added some typecasts to avoid compiler warnings.
+ *
+ *	Revision 1.82  2002/11/13 09:20:46  rschmidt
+ *	Replaced for(..) with do {} while (...) in SkXmUpdateStats().
+ *	Replaced 2 macros GM_IN16() with 1 GM_IN32() in SkGmMacStatistic().
+ *	Added SkGmCableDiagStatus() for Virtual Cable Test (VCT).
+ *	Editorial changes.
+ *
+ *	Revision 1.81  2002/10/28 14:28:08  rschmidt
+ *	Changed MAC address setup for GMAC in SkGmInitMac().
+ *	Optimized handling of counter overflow IRQ in SkGmOverflowStatus().
+ *	Editorial changes.
+ *
+ *	Revision 1.80  2002/10/14 15:29:44  rschmidt
+ *	Corrected disabling of all PHY IRQs.
+ *	Added WA for deviation #16 (address used for pause packets).
+ *	Set Pause Mode in SkMacRxTxEnable() only for Genesis.
+ *	Added IRQ and counter for Receive FIFO Overflow in DEBUG-mode.
+ *	SkXmTimeStamp() replaced by SkMacTimeStamp().
+ *	Added clearing of GMAC Tx FIFO Underrun IRQ in SkGmIrq().
+ *	Editorial changes.
+ *
+ *	Revision 1.79  2002/10/10 15:55:36  mkarl
+ *	changes for PLinkSpeedUsed
+ *
+ *	Revision 1.78  2002/09/12 09:39:51  rwahl
+ *	Removed deactivate code for SIRQ overflow event separate for TX/RX.
+ *
+ *	Revision 1.77  2002/09/09 12:26:37  mkarl
+ *	added handling for Yukon to SkXmTimeStamp
+ *
+ *	Revision 1.76  2002/08/21 16:41:16  rschmidt
+ *	Added bit GPC_ENA_XC (Enable MDI crossover) in HWCFG_MODE.
+ *	Added forced speed settings in SkGmInitPhyMarv().
+ *	Added settings of full/half duplex capabilities for YUKON Fiber.
+ *	Editorial changes.
+ *
+ *	Revision 1.75  2002/08/16 15:12:01  rschmidt
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Added function SkMacHashing() for ADDR-Module.
+ *	Removed functions SkXmClrSrcCheck(), SkXmClrHashAddr() (calls replaced
+ *	with macros).
+ *	Removed functions SkGmGetMuxConfig().
+ *	Added HWCFG_MODE init for YUKON Fiber.
+ *	Changed initialization of GPHY in SkGmInitPhyMarv().
+ *	Changed check of parameter in SkXmMacStatistic().
+ *	Editorial changes.
+ *
+ *	Revision 1.74  2002/08/12 14:00:17  rschmidt
+ *	Replaced usage of Broadcom PHY Ids with defines.
+ *	Corrected error messages in SkGmMacStatistic().
+ *	Made SkMacPromiscMode() public for ADDR-Modul.
+ *	Editorial changes.
+ *
+ *	Revision 1.73  2002/08/08 16:26:24  rschmidt
+ *	Improved reset sequence for YUKON in SkGmHardRst() and SkGmInitMac().
+ *	Replaced XMAC Rx High Watermark init value with SK_XM_RX_HI_WM.
+ *	Editorial changes.
+ *
+ *	Revision 1.72  2002/07/24 15:11:19  rschmidt
+ *	Fixed wrong placement of parenthesis.
+ *	Editorial changes.
+ *
+ *	Revision 1.71  2002/07/23 16:05:18  rschmidt
+ *	Added global functions for PHY: SkGePhyRead(), SkGePhyWrite().
+ *	Fixed Tx Counter Overflow IRQ (Bug ID #10730).
+ *	Editorial changes.
+ *
+ *	Revision 1.70  2002/07/18 14:27:27  rwahl
+ *	Fixed syntax error.
+ *
+ *	Revision 1.69  2002/07/17 17:08:47  rwahl
+ *	Fixed check in SkXmMacStatistic().
+ *
+ *	Revision 1.68  2002/07/16 07:35:24  rwahl
+ *	Removed check for cleared mib counter in SkGmResetCounter().
+ *
+ *	Revision 1.67  2002/07/15 18:35:56  rwahl
+ *	Added SkXmUpdateStats(), SkGmUpdateStats(), SkXmMacStatistic(),
+ *	  SkGmMacStatistic(), SkXmResetCounter(), SkGmResetCounter(),
+ *	  SkXmOverflowStatus(), SkGmOverflowStatus().
+ *	Changes to SkXmIrq() & SkGmIrq(): Combined SIRQ Overflow for both
+ *	  RX & TX.
+ *	Changes to SkGmInitMac(): call to SkGmResetCounter().
+ *	Editorial changes.
+ *
+ *	Revision 1.66  2002/07/15 15:59:30  rschmidt
+ *	Added PHY Address in SkXmPhyRead(), SkXmPhyWrite().
+ *	Added MIB Clear Counter in SkGmInitMac().
+ *	Added Duplex and Flow-Control settings.
+ *	Reset all Multicast filtering Hash reg. in SkGmInitMac().
+ *	Added new function: SkGmGetMuxConfig().
+ *	Editorial changes.
+ *
+ *	Revision 1.65  2002/06/10 09:35:39  rschmidt
+ *	Replaced C++ comments (//).
+ *	Added #define VCPU around VCPUwaitTime.
+ *	Editorial changes.
+ *
+ *	Revision 1.64  2002/06/05 08:41:10  rschmidt
+ *	Added function for XMAC2: SkXmTimeStamp().
+ *	Added function for YUKON: SkGmSetRxCmd().
+ *	Changed SkGmInitMac() resp. SkGmHardRst().
+ *	Fixed wrong variable in SkXmAutoNegLipaXmac() (debug mode).
+ *	SkXmRxTxEnable() replaced by SkMacRxTxEnable().
+ *	Editorial changes.
+ *
+ *	Revision 1.63  2002/04/25 13:04:44  rschmidt
+ *	Changes for handling YUKON.
+ *	Use of #ifdef OTHER_PHY to eliminate code for unused Phy types.
+ *	Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced
+ *	by functions SkXmPhyRead(), SkXmPhyWrite();
+ *	Removed use of PRxCmd to setup XMAC.
+ *	Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res.
+ *	Added setting of XM_RX_DIS_CEXT in SkXmInitMac().
+ *	Removed status parameter from MAC IRQ handler SkMacIrq(),
+ *	SkXmIrq() and SkGmIrq().
+ *	SkXmAutoNegLipa...() for ext. Phy replaced by SkMacAutoNegLipaPhy().
+ *	Added SkMac...() functions to handle both XMAC and GMAC.
+ *	Added functions for YUKON: SkGmHardRst(), SkGmSoftRst(),
+ *	SkGmSetRxTxEn(), SkGmIrq(), SkGmInitMac(), SkGmInitPhyMarv(),
+ *	SkGmAutoNegDoneMarv(), SkGmPhyRead(), SkGmPhyWrite().
+ *	Changes for V-CPU support.
+ *	Editorial changes.
+ *
+ *	Revision 1.62  2001/08/06 09:50:14  rschmidt
+ *	Workaround BCOM Errata #1 for the C5 type.
+ *	Editorial changes.
+ *
+ *	Revision 1.61  2001/02/09 15:40:59  rassmann
+ *	Editorial changes.
+ *
+ *	Revision 1.60  2001/02/07 15:02:01  cgoos
+ *	Added workaround for Fujitsu switch link down.
+ *
+ *	Revision 1.59  2001/01/10 09:38:06  cgoos
+ *	Fixed Broadcom C0/A1 Id check for workaround.
+ *
+ *	Revision 1.58  2000/11/29 11:30:38  cgoos
+ *	Changed DEBUG sections with NW output to xDEBUG
+ *
+ *	Revision 1.57  2000/11/27 12:40:40  rassmann
+ *	Suppressing preamble after first access to BCom, not before (#10556).
+ *
+ *	Revision 1.56  2000/11/09 12:32:48  rassmann
+ *	Renamed variables.
+ *
+ *	Revision 1.55  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *
+ *	Revision 1.54  2000/10/02 14:10:27  rassmann
+ *	Reading BCOM PHY after releasing reset until it returns a valid value.
+ *
+ *	Revision 1.53  2000/07/27 12:22:11  gklug
+ *	fix: possible endless loop in XmHardRst.
+ *
+ *	Revision 1.52  2000/05/22 08:48:31  malthoff
+ *	Fix: #10523 errata valid for all BCOM PHYs.
+ *
+ *	Revision 1.51  2000/05/17 12:52:18  malthoff
+ *	Fixes BCom link errata (#10523).
+ *
+ *	Revision 1.50  1999/11/22 13:40:14  cgoos
+ *	Changed license header to GPL.
+ *
+ *	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 dependent.
+ *
+ *	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 independent
+ *	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 <config.h>
+
+#ifdef CONFIG_SK98
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* typedefs *******************************************************************/
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+	int		PhyReg;		/* Phy register */
+	SK_U16	PhyVal;		/* Value to write */
+} BCOM_HACK;
+
+/* local variables ************************************************************/
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skxmac2.c,v 1.91 2003/02/05 15:09:34 rschmidt Exp $ (C) SK ";
+
+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	SkGmInitPhyMarv(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	SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
+#ifdef OTHER_PHY
+static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkXmPhyRead() - Read from XMAC PHY register
+ *
+ * Description:	reads a 16-bit word from XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmPhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
+{
+	SK_U16		Mmu;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+
+	/* get the PHY register's value */
+	XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Ready' is set */
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);
+
+		/* get the PHY register's value */
+		XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+	}
+}	/* SkXmPhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkXmPhyWrite() - Write to XMAC PHY register
+ *
+ * Description:	writes a 16-bit word to XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16		Mmu;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+	}
+
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+
+	/* write the PHY register's value */
+	XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
+
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+	}
+}	/* SkXmPhyWrite */
+
+
+/******************************************************************************
+ *
+ *	SkGmPhyRead() - Read from GPHY register
+ *
+ * Description:	reads a 16-bit word from GPHY through MDIO
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmPhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
+{
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	u_long SimCyle;
+	u_long SimLowTime;
+
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, SimCyle, SimLowTime);
+#endif /* VCPU */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* set PHY-Register offset and 'Read' OpCode (= 1) */
+	*pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) |
+		GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD);
+
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);
+
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		*pVal = 0;
+		return;
+	}
+
+	*pVal |= GM_SMI_CT_BUSY;
+
+	do {
+#ifdef VCPU
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'ReadValid' is set */
+	} while (Ctrl == *pVal);
+
+	/* get the PHY register's value */
+	GM_IN16(IoC, Port, GM_SMI_DATA, pVal);
+
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+}	/* SkGmPhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkGmPhyWrite() - Write to GPHY register
+ *
+ * Description:	writes a 16-bit word to GPHY through MDIO
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	SK_U32	DWord;
+	u_long	SimCyle;
+	u_long	SimLowTime;
+
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, Val, SimCyle, SimLowTime);
+#endif /* VCPU */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* write the PHY register's value */
+	GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
+
+	/* set PHY-Register offset and 'Write' OpCode (= 0) */
+	Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);
+
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);
+
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		return;
+	}
+
+	Val |= GM_SMI_CT_BUSY;
+
+	do {
+#ifdef VCPU
+		/* read Timer value */
+		SK_IN32(IoC, B2_TI_VAL, &DWord);
+
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'Busy' is cleared */
+	} while (Ctrl == Val);
+
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+}	/* SkGmPhyWrite */
+
+
+/******************************************************************************
+ *
+ *	SkGePhyRead() - Read from PHY register
+ *
+ * Description:	calls a read PHY routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
+{
+	void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);
+
+	if (pAC->GIni.GIGenesis) {
+		r_func = SkXmPhyRead;
+	}
+	else {
+		r_func = SkGmPhyRead;
+	}
+
+	r_func(pAC, IoC, Port, PhyReg, pVal);
+}	/* SkGePhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkGePhyWrite() - Write to PHY register
+ *
+ * Description:	calls a write PHY routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);
+
+	if (pAC->GIni.GIGenesis) {
+		w_func = SkXmPhyWrite;
+	}
+	else {
+		w_func = SkGmPhyWrite;
+	}
+
+	w_func(pAC, IoC, Port, PhyReg, Val);
+}	/* SkGePhyWrite */
+
+
+/******************************************************************************
+ *
+ *	SkMacPromiscMode() - Enable / Disable Promiscuous Mode
+ *
+ * Description:
+ *   enables / disables promiscuous mode by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacPromiscMode(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U16	RcReg;
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable promiscuous mode */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_PROM;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_PROM;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+
+		/* enable or disable unicast and multicast filtering */
+		if (Enable) {
+			RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		else {
+			RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+}	/* SkMacPromiscMode*/
+
+
+/******************************************************************************
+ *
+ *	SkMacHashing() - Enable / Disable Hashing
+ *
+ * Description:
+ *   enables / disables hashing by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacHashing(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U16	RcReg;
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable hashing */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_HASH;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_HASH;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+
+		/* enable or disable multicast filtering */
+		if (Enable) {
+			RcReg |= GM_RXCR_MCF_ENA;
+		}
+		else {
+			RcReg &= ~GM_RXCR_MCF_ENA;
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+}	/* SkMacHashing*/
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
+ *
+ * Description:
+ *	The features
+ *	 - FCS stripping,					SK_STRIP_FCS_ON/OFF
+ *	 - pad byte stripping,				SK_STRIP_PAD_ON/OFF
+ *	 - don't set XMR_FS_ERR in status	SK_LENERR_OK_ON/OFF
+ *	   for inrange length error frames
+ *	 - don't set XMR_FS_ERR in status	SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *	for incoming 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 written to the Rx Command register immediately.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+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_U16	OldRxCmd;
+	SK_U16	RxCmd;
+
+	XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);
+
+	RxCmd = OldRxCmd;
+
+	switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+	case SK_STRIP_FCS_ON:
+		RxCmd |= XM_RX_STRIP_FCS;
+		break;
+	case SK_STRIP_FCS_OFF:
+		RxCmd &= ~XM_RX_STRIP_FCS;
+		break;
+	}
+
+	switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+	case SK_STRIP_PAD_ON:
+		RxCmd |= XM_RX_STRIP_PAD;
+		break;
+	case SK_STRIP_PAD_OFF:
+		RxCmd &= ~XM_RX_STRIP_PAD;
+		break;
+	}
+
+	switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+	case SK_LENERR_OK_ON:
+		RxCmd |= XM_RX_LENERR_OK;
+		break;
+	case SK_LENERR_OK_OFF:
+		RxCmd &= ~XM_RX_LENERR_OK;
+		break;
+	}
+
+	switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+	case SK_BIG_PK_OK_ON:
+		RxCmd |= XM_RX_BIG_PK_OK;
+		break;
+	case SK_BIG_PK_OK_OFF:
+		RxCmd &= ~XM_RX_BIG_PK_OK;
+		break;
+	}
+
+	switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
+	case SK_SELF_RX_ON:
+		RxCmd |= XM_RX_SELF_RX;
+		break;
+	case SK_SELF_RX_OFF:
+		RxCmd &= ~XM_RX_SELF_RX;
+		break;
+	}
+
+	/* Write the new mode to the Rx command register if required */
+	if (OldRxCmd != RxCmd) {
+		XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
+	}
+}	/* SkXmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
+ *
+ * Description:
+ *	The features
+ *	 - FCS (CRC) stripping,				SK_STRIP_FCS_ON/OFF
+ *	 - don't set GMR_FS_LONG_ERR		SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *	for incoming 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 written to the Rx Command register immediately.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+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_U16	OldRxCmd;
+	SK_U16	RxCmd;
+
+	if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
+
+		GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_STRIP_FCS_ON) != 0) {
+			RxCmd |= GM_RXCR_CRC_DIS;
+		}
+		else {
+			RxCmd &= ~GM_RXCR_CRC_DIS;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
+		}
+	}
+
+	if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
+
+		GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_BIG_PK_OK_ON) != 0) {
+			RxCmd |= GM_SMOD_JUMBO_ENA;
+		}
+		else {
+			RxCmd &= ~GM_SMOD_JUMBO_ENA;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
+		}
+	}
+}	/* SkGmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
+ *
+ * Description:	modifies the MAC's Rx Control reg. dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Mode)		/* Rx Mode */
+{
+	if (pAC->GIni.GIGenesis) {
+
+		SkXmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+	else {
+
+		SkGmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+}	/* SkMacSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacCrcGener() - Enable / Disable CRC Generation
+ *
+ * Description:	enables / disables CRC generation dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacCrcGener(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U16	Word;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN16(IoC, Port, XM_TX_CMD, &Word);
+
+		if (Enable) {
+			Word &= ~XM_TX_NO_CRC;
+		}
+		else {
+			Word |= XM_TX_NO_CRC;
+		}
+		/* setup Tx Command Register */
+		XM_OUT16(pAC, Port, XM_TX_CMD, Word);
+	}
+	else {
+
+		GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
+
+		if (Enable) {
+			Word &= ~GM_TXCR_CRC_DIS;
+		}
+		else {
+			Word |= GM_TXCR_CRC_DIS;
+		}
+		/* setup Tx Control Register */
+		GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
+	}
+}	/* SkMacCrcGener*/
+
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ *	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,		/* Port Index (MAC_1 + n) */
+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]);
+	}
+}	/* SkXmClrExactAddr */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
+ *
+ * Description:
+ *	Flush the transmit FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacFlushTxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
+	}
+	else {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+}	/* SkMacFlushTxFifo */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushRxFifo() - Flush the MAC's receive FIFO
+ *
+ * Description:
+ *	Flush the receive FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacFlushRxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
+	}
+	else {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+}	/* SkMacFlushRxFifo */
+
+
+/******************************************************************************
+ *
+ *	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 machine,
+ *		- resetting 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 machine 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
+ */
+static void SkXmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+
+	/* reset the statistics module */
+	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+	/* disable all XMAC IRQs */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+
+	XM_OUT32(IoC, Port, XM_MODE, 0);		/* clear Mode Reg */
+
+	XM_OUT16(IoC, Port, XM_TX_CMD, 0);		/* reset TX CMD Reg */
+	XM_OUT16(IoC, Port, XM_RX_CMD, 0);		/* reset RX CMD Reg */
+
+	/* disable all PHY IRQs */
+	switch (pAC->GIni.GP[Port].PhyType) {
+	case SK_PHY_BCOM:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+			break;
+		case SK_PHY_NAT:
+			/* todo: National
+			 SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+			break;
+#endif /* OTHER_PHY */
+	}
+
+	/* clear the Hash Register */
+	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+
+	/* clear the Exact Match Address registers */
+	SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+
+	/* clear the Source Check Address registers */
+	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+
+}	/* SkXmSoftRst */
+
+
+/******************************************************************************
+ *
+ *	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).
+ *
+ * ATTENTION:
+ * 	It is absolutely necessary to reset the SW_RST Bit first
+ *	before calling this function.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	Reg;
+	int		i;
+	int		TOut;
+	SK_U16	Word;
+
+	for (i = 0; i < 4; i++) {
+		/* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+		TOut = 0;
+		do {
+			if (TOut++ > 10000) {
+				/*
+				 * Adapter seems to be in RESET state.
+				 * Registers cannot be written.
+				 */
+				return;
+			}
+
+			SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+
+			SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
+
+		} while ((Word & MFF_SET_MAC_RST) == 0);
+	}
+
+	/* For external PHYs there must be special handling */
+	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);
+	}
+
+}	/* SkXmHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkGmSoftRst() - Do a GMAC software reset
+ *
+ * Description:
+ *	The GPHY registers should not be destroyed during this
+ *	kind of software reset.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	SK_U16  RxCtrl;
+
+	/* reset the statistics module */
+
+	/* disable all GMAC IRQs */
+	SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+
+	/* disable all PHY IRQs */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+
+	/* clear the Hash Register */
+	GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash);
+
+	/* Enable Unicast and Multicast filtering */
+	GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
+
+	GM_OUT16(IoC, Port, GM_RX_CTRL,
+		RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+
+}	/* SkGmSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkGmHardRst() - Do a GMAC hardware reset
+ *
+ * Description:
+ *
+ * ATTENTION:
+ * 	It is absolutely necessary to reset the SW_RST Bit first
+ *	before calling this function.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	/* set GPHY Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+	/* set GMAC Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+}	/* SkGmHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkMacSoftRst() - Do a MAC software reset
+ *
+ * Description:	calls a MAC software reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSoftRst(
+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];
+
+	/* disable receiver and transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
+
+	if (pAC->GIni.GIGenesis) {
+
+		SkXmSoftRst(pAC, IoC, Port);
+	}
+	else {
+
+		SkGmSoftRst(pAC, IoC, Port);
+	}
+
+	/* flush the MAC's Rx and Tx FIFOs */
+	SkMacFlushTxFifo(pAC, IoC, Port);
+
+	SkMacFlushRxFifo(pAC, IoC, Port);
+
+	pPrt->PState = SK_PRT_STOP;
+
+}	/* SkMacSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkMacHardRst() - Do a MAC hardware reset
+ *
+ * Description:	calls a MAC hardware reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+
+	if (pAC->GIni.GIGenesis) {
+
+		SkXmHardRst(pAC, IoC, Port);
+	}
+	else {
+
+		SkGmHardRst(pAC, IoC, Port);
+	}
+
+	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+
+}	/* SkMacHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ *	Initialize the XMAC of the specified port.
+ *	The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The XMAC's 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_U32		Reg;
+	int			i;
+	SK_U16		SWord;
+
+	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 & MFF_SET_MAC_RST) != 0) {
+			/* 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), MFF_CLR_MAC_RST);
+
+		/* Ensure that XMAC reset release is done (errata from LReinbold?) */
+		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+
+		/* Clear PHY reset */
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+
+			SK_IN32(IoC, B2_GP_IO, &Reg);
+
+			if (Port == 0) {
+				Reg |= (GP_DIR_0 | GP_IO_0); /* set to output */
+			}
+			else {
+				Reg |= (GP_DIR_2 | GP_IO_2); /* set to output */
+			}
+			SK_OUT32(IoC, B2_GP_IO, Reg);
+
+			/* Enable GMII interface */
+			XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+
+			/* read Id from external PHY (all have the same address) */
+			SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);
+
+			/*
+			 * Optimize MDIO transfer by suppressing preamble.
+			 * Must be done AFTER first access to BCOM chip.
+			 */
+			XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+
+			XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+			if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
+				/*
+				 * Workaround BCOM Errata for the C0 type.
+				 * Write magic patterns to reserved registers.
+				 */
+				i = 0;
+				while (BcomRegC0Hack[i].PhyReg != 0) {
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
+						BcomRegC0Hack[i].PhyVal);
+					i++;
+				}
+			}
+			else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
+				/*
+				 * Workaround BCOM Errata for the A1 type.
+				 * Write magic patterns to reserved registers.
+				 */
+				i = 0;
+				while (BcomRegA1Hack[i].PhyReg != 0) {
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
+						BcomRegA1Hack[i].PhyVal);
+					i++;
+				}
+			}
+
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom PHYs.
+			 * Disable Power Management after reset.
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord | PHY_B_AC_DIS_PM));
+
+			/* PHY LED initialization is done in SkGeXmitLED() */
+		}
+
+		/* Dummy read the Interrupt source register */
+		XM_IN16(IoC, Port, XM_ISRC, &SWord);
+
+		/*
+		 * The auto-negotiation process starts immediately after
+		 * clearing the reset. The auto-negotiation process should be
+		 * started by the SIRQ, therefore stop it here immediately.
+		 */
+		SkMacInitPhy(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 programmed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
+	 */
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independent. 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, SK_XM_RX_HI_WM);
+
+	/* Configure Tx Request Threshold */
+	SWord = SK_XM_THR_SL;				/* for single port */
+
+	if (pAC->GIni.GIMacsFound > 1) {
+		switch (pAC->GIni.GIPortUsage) {
+		case SK_RED_LINK:
+			SWord = SK_XM_THR_REDL;		/* redundant link */
+			break;
+		case SK_MUL_LINK:
+			SWord = SK_XM_THR_MULL;		/* load balancing */
+			break;
+		case SK_JUMBO_LINK:
+			SWord = SK_XM_THR_JUMBO;	/* jumbo frames */
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
+			break;
+		}
+	}
+	XM_OUT16(IoC, Port, XM_TX_THR, SWord);
+
+	/* setup register defaults for the Tx Command Register */
+	XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+	/* setup register defaults for the Rx Command Register */
+	SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		SWord |= XM_RX_BIG_PK_OK;
+	}
+
+	if (pPrt->PLinkModeConf == SK_LMODE_HALF) {
+		/*
+		 * If in manual half duplex mode the other side might be in
+		 * full duplex mode, so ignore if a carrier extension is not seen
+		 * on frames received
+		 */
+		SWord |= XM_RX_DIS_CEXT;
+	}
+
+	XM_OUT16(IoC, Port, XM_RX_CMD, SWord);
+
+	/*
+	 * 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!
+	 */
+
+	/*
+	 * 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 auto-negotiation process
+	 * has been completed successfully.
+	 */
+}	/* SkXmInitMac */
+
+/******************************************************************************
+ *
+ *	SkGmInitMac() - Initialize the GMAC
+ *
+ * Description:
+ *	Initialize the GMAC of the specified port.
+ *	The GMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The GMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int			i;
+	SK_U16		SWord;
+	SK_U32		DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
+
+		if ((DWord & GMC_RST_SET) != 0) {
+			/* 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) {
+		/* set GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+		/* set GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+		/* clear GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);
+
+		/* set GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+		/* set HWCFG_MODE */
+		DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+			GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
+			(pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
+			GPC_HWCFG_GMII_FIB);
+
+		/* set GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);
+
+		/* release GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);
+
+		/* clear GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+		/* Dummy read the Interrupt source register */
+		SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
+
+#ifndef VCPU
+		/* read Id from PHY */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
+
+		SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
+#endif /* VCPU */
+	}
+
+	(void)SkGmResetCounter(pAC, IoC, Port);
+
+	SWord =  0;
+
+	/* speed settings */
+	switch (pPrt->PLinkSpeed) {
+	case SK_LSPEED_AUTO:
+	case SK_LSPEED_1000MBPS:
+		SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100;
+		break;
+	case SK_LSPEED_100MBPS:
+		SWord |= GM_GPCR_SPEED_100;
+		break;
+	case SK_LSPEED_10MBPS:
+		break;
+	}
+
+	/* duplex settings */
+	if (pPrt->PLinkMode != SK_LMODE_HALF) {
+		/* set full duplex */
+		SWord |= GM_GPCR_DUP_FULL;
+	}
+
+	/* flow control settings */
+	switch (pPrt->PFlowCtrlMode) {
+	case SK_FLOW_MODE_NONE:
+		/* disable auto-negotiation for flow-control */
+		SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS;
+		break;
+	case SK_FLOW_MODE_LOC_SEND:
+		SWord |= GM_GPCR_FC_RX_DIS;
+		break;
+	case SK_FLOW_MODE_SYMMETRIC:
+		/* TBD */
+	case SK_FLOW_MODE_SYM_OR_REM:
+		/* enable auto-negotiation for flow-control and */
+		/* enable Rx and Tx of pause frames */
+		break;
+	}
+
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		/* disable auto-update for speed, duplex and flow-control */
+		SWord |= GM_GPCR_AU_ALL_DIS;
+	}
+
+	/* setup General Purpose Control Register */
+	GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+	/* setup Transmit Control Register */
+	GM_OUT16(IoC, Port, GM_TX_CTRL, GM_TXCR_COL_THR);
+
+	/* setup Receive Control Register */
+	GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
+		GM_RXCR_CRC_DIS);
+
+	/* setup Transmit Flow Control Register */
+	GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* setup Transmit Parameter Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
+#endif /* VCPU */
+
+	SWord = JAM_LEN_VAL(3) | JAM_IPG_VAL(11) | IPG_JAM_DATA(26);
+
+	GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);
+
+	/* configure the Serial Mode Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
+#endif /* VCPU */
+
+	SWord = GM_SMOD_VLAN_ENA | IPG_VAL_FAST_ETH;
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* enable jumbo mode (Max. Frame Length = 9018) */
+		SWord |= GM_SMOD_JUMBO_ENA;
+	}
+
+	GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
+
+	/*
+	 * configure the GMACs Station Addresses
+	 * in PROM you can find our addresses at:
+	 * B2_MAC_1 = xx xx xx xx xx x0 virtual address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
+	 */
+
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independent. Remember this when changing.
+		 */
+		/* physical address: will be used for pause frames */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+#ifdef WA_DEV_16
+		/* WA for deviation #16 */
+		if (pAC->GIni.GIChipRev == 0) {
+			/* swap the address bytes */
+			SWord = ((SWord & 0xff00) >> 8)	| ((SWord & 0x00ff) << 8);
+
+			/* write to register in reversed order */
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
+		}
+		else {
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+		}
+#else
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+#endif /* WA_DEV_16 */
+
+		/* virtual address: will be used for data */
+		SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);
+
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
+
+		/* reset Multicast filtering Hash registers 1-3 */
+		GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0);
+	}
+
+	/* reset Multicast filtering Hash register 4 */
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);
+
+	/* enable interrupt mask for counter overflows */
+	GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);
+
+	/* read General Purpose Status */
+	GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("MAC Stat Reg=0x%04X\n", SWord));
+
+#ifdef SK_DIAG
+	c_print("MAC Stat Reg=0x%04X\n", SWord);
+#endif /* SK_DIAG */
+
+}	/* SkGmInitMac */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ *	This function initializes the XMACs Duplex Mode.
+ *	It should be called after successfully finishing
+ *	the Auto-negotiation 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 probable not quick
+		 * 	enough at the 'XMAC' bus to burst 8kB.
+		 *	The XMAC stops 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;
+	}
+}	/* SkXmInitDupMd */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ *	This function initializes the Pause Mode which should
+ *	be used for this port.
+ *	It should be called after successfully finishing
+ *	the Auto-negotiation 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_U32		DWord;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/* Disable Pause Frame Reception */
+		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 */
+		Word &= ~XM_MMU_IGN_PF;
+	}
+
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word);
+
+	XM_IN32(IoC, Port, XM_MODE, &DWord);
+
+	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 triggered.
+		 * Send a Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition occurs.
+		 * Send a zero pause time frame to re-start transmission.
+		 */
+
+		/* 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 */
+		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 */
+		DWord &= ~XM_PAUSE_MODE;
+
+		/* Disable Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+
+	XM_OUT32(IoC, Port, XM_MODE, DWord);
+}	/* SkXmInitPauseMd*/
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyXmac() - Initialize the XMAC Phy registers
+ *
+ * Description:	initializes 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 LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl;
+
+	pPrt = &pAC->GIni.GP[Port];
+	Ctrl = 0;
+
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyXmac: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			Ctrl |= PHY_CT_DUP_MD;
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation 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 auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl |= PHY_X_AN_HD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl |= PHY_X_AN_FD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl |= 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:
+			Ctrl |= PHY_X_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl |= PHY_X_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl |= PHY_X_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl |= 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 */
+		SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);
+
+		/* Restart Auto-negotiation */
+		Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
+}	/* SkXmInitPhyXmac */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description:	initializes 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 LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+	SK_U16		Ctrl4;
+	SK_U16		Ctrl5;
+
+	Ctrl1 = PHY_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
+	Ctrl4 = PHY_B_PEC_EN_LTR;
+	Ctrl5 = PHY_B_AC_TX_TST;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Ctrl2 |= PHY_B_1000C_MSE;
+
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Ctrl2 |= PHY_B_1000C_MSC;
+		}
+	}
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyBcom: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation 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 auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/*
+		 * Workaround BCOM Errata #1 for the C5 type.
+		 * 1000Base-T Link Acquisition Failure in Slave Mode
+		 * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+		 */
+		Ctrl2 |= PHY_B_1000C_RD;
+
+		 /* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl2 |= PHY_B_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl2 |= PHY_B_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl2 |= 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:
+			Ctrl3 |= PHY_B_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl3 |= PHY_B_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl3 |= PHY_B_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl3 |= PHY_B_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Auto-negotiation */
+		Ctrl1 |= 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 */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+
+	/* Write AutoNeg Advertisement Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Adv. Reg=0x%04X\n", Ctrl3));
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* configure FIFO to high latency for transmission of ext. packets */
+		Ctrl4 |= PHY_B_PEC_HIGH_LA;
+
+		/* configure reception of extended packets */
+		Ctrl5 |= PHY_B_AC_LONG_PACK;
+
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+	}
+
+	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyBcom */
+
+
+/******************************************************************************
+ *
+ *	SkGmInitPhyMarv() - Initialize the Marvell Phy registers
+ *
+ * Description:	initializes all the Marvell Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmInitPhyMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		PhyCtrl;
+	SK_U16		C1000BaseT;
+	SK_U16		AutoNegAdv;
+	SK_U16		ExtPhyCtrl;
+	SK_U16		PhyStat;
+	SK_U16		PhyStat1;
+	SK_U16		PhySpecStat;
+	SK_U16		LedCtrl;
+	SK_BOOL		AutoNeg;
+
+#ifdef VCPU
+	VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
+		Port, DoLoop);
+#else /* VCPU */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	}
+	else {
+		AutoNeg = SK_TRUE;
+	}
+
+	if (!DoLoop) {
+		/* Read Ext. PHY Specific Control */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+
+		ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			PHY_M_EC_MAC_S_MSK);
+
+		ExtPhyCtrl |= PHY_M_EC_M_DSC(1) | PHY_M_EC_S_DSC(1) |
+			PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
+
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Ext.PHYCtrl=0x%04X\n", ExtPhyCtrl));
+
+		/* Read PHY Control */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+
+		/* Assert software reset */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL,
+			(SK_U16)(PhyCtrl | PHY_CT_RESET));
+	}
+#endif /* VCPU */
+
+	PhyCtrl = 0 /* PHY_CT_COL_TST */;
+	C1000BaseT = 0;
+	AutoNegAdv = PHY_SEL_TYPE;
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		/* enable Manual Master/Slave */
+		C1000BaseT |= PHY_M_1000C_MSE;
+
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			C1000BaseT |= PHY_M_1000C_MSC;	/* set it to Master */
+		}
+	}
+
+	/* Auto-negotiation ? */
+	if (!AutoNeg) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyMarv: no auto-negotiation Port %d\n", Port));
+
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			/* Set Full Duplex Mode */
+			PhyCtrl |= PHY_CT_DUP_MD;
+		}
+
+		/* Set Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			C1000BaseT |= PHY_M_1000C_MSE;	/* set it to Slave */
+		}
+
+		/* Set Speed */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+		case SK_LSPEED_1000MBPS:
+			PhyCtrl |= PHY_CT_SP1000;
+			break;
+		case SK_LSPEED_100MBPS:
+			PhyCtrl |= PHY_CT_SP100;
+			break;
+		case SK_LSPEED_10MBPS:
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+				SKERR_HWI_E019MSG);
+		}
+
+		if (!DoLoop) {
+			PhyCtrl |= PHY_CT_RESET;
+		}
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyMarv: with auto-negotiation Port %d\n", Port));
+
+		PhyCtrl |= PHY_CT_ANE;
+
+		if (pAC->GIni.GICopperType) {
+			/* Set Speed capabilities */
+			switch (pPrt->PLinkSpeed) {
+			case SK_LSPEED_AUTO:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_1000MBPS:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				break;
+			case SK_LSPEED_100MBPS:
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_10MBPS:
+				AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+					SKERR_HWI_E019MSG);
+			}
+
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				C1000BaseT &= ~PHY_M_1000C_AFD;
+				AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
+				break;
+			case SK_LMODE_AUTOFULL:
+				C1000BaseT &= ~PHY_M_1000C_AHD;
+				AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
+				break;
+			case SK_LMODE_AUTOBOTH:
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+
+			/* Set Auto-negotiation advertisement */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_B_P_NO_PAUSE;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_B_P_ASYM_MD;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_B_P_SYM_MD;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_B_P_BOTH_MD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
+		else {	/* special defines for FIBER (88E1011S only) */
+
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD;
+				break;
+			case SK_LMODE_AUTOFULL:
+				AutoNegAdv |= PHY_M_AN_1000X_AFD;
+				break;
+			case SK_LMODE_AUTOBOTH:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+
+			/* Set Auto-negotiation advertisement */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_M_P_ASYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_M_P_SYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_M_P_BOTH_MD_X;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
+
+		if (!DoLoop) {
+			/* Restart Auto-negotiation */
+			PhyCtrl |= PHY_CT_RE_CFG;
+		}
+	}
+
+#ifdef VCPU
+	/*
+	 * E-mail from Gu Lin (08-03-2002):
+	 */
+
+	/* Program PHY register 30 as 16'h0708 for simulation speed up */
+	SkGmPhyWrite(pAC, IoC, Port, 30, 0x0708);
+
+	VCpuWait(2000);
+
+#else /* VCPU */
+
+	/* Write 1000Base-T Control Register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl=0x%04X\n", C1000BaseT));
+
+	/* Write AutoNeg Advertisement Register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg.Ad.=0x%04X\n", AutoNegAdv));
+#endif /* VCPU */
+
+	if (DoLoop) {
+		/* Set the PHY Loopback bit */
+		PhyCtrl |= PHY_CT_LOOP;
+
+		/* Program PHY register 16 as 16'h0400 to force link good */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
+
+#if 0
+		if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
+			/* Write Ext. PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
+				(SK_U16)((pPrt->PLinkSpeed + 2) << 4));
+		}
+	}
+	else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
+			/* Write PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_EN_DET_MSK);
+		}
+#endif /* 0 */
+	}
+
+	/* Write to the PHY Control register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+
+#ifdef VCPU
+	VCpuWait(2000);
+#else
+
+	LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS);
+
+#ifdef ACT_LED_BLINK
+	LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL;
+#endif /* ACT_LED_BLINK */
+
+#ifdef DUP_LED_NORMAL
+	LedCtrl |= PHY_M_LEDC_DP_CTRL;
+#endif /* DUP_LED_NORMAL */
+
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl);
+
+#endif /* VCPU */
+
+#ifdef SK_DIAG
+	c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl);
+	c_print("Set 1000 B-T=0x%04X\n", C1000BaseT);
+	c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv);
+	c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl);
+#endif /* SK_DIAG */
+
+#ifndef xDEBUG
+	/* Read PHY Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+
+	/* Read 1000Base-T Control Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl =0x%04X\n", C1000BaseT));
+
+	/* Read AutoNeg Advertisement Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Ad.=0x%04X\n", AutoNegAdv));
+
+	/* Read Ext. PHY Specific Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Ext PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+
+	/* Read PHY Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat));
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat1));
+
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Spec Stat=0x%04X\n", PhySpecStat));
+#endif /* DEBUG */
+
+#ifdef SK_DIAG
+	c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
+	c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
+	c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
+	c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
+	c_print("PHY Spec Reg=0x%04X\n", PhySpecStat);
+#endif /* SK_DIAG */
+
+}	/* SkGmInitPhyMarv */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description:	initializes 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 LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+
+	Ctrl1 = PHY_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Ctrl2 |= PHY_L_1000C_MSE;
+
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Ctrl2 |= PHY_L_1000C_MSC;
+		}
+	}
+	/* Auto-negotiation ? */
+	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_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyLone: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Ctrl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation 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 auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl2 |= PHY_L_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl2 |= PHY_L_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl2 |= 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:
+			Ctrl3 |= PHY_L_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl3 |= PHY_L_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl3 |= PHY_L_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl3 |= PHY_L_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Auto-negotiation */
+		Ctrl1 = 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 */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+
+	/* Write AutoNeg Advertisement Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Adv. Reg=0x%04X\n", Ctrl3));
+
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl1 |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyLone */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description:	initializes 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 LoopBack be set-up? */
+{
+/* todo: National */
+}	/* SkXmInitPhyNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkMacInitPhy() - Initialize the PHY registers
+ *
+ * Description:	calls the Init PHY routines dep. on board type
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacInitPhy(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack 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_MARV_COPPER:
+	case SK_PHY_MARV_FIBER:
+		SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
+		break;
+#ifdef OTHER_PHY
+	case SK_PHY_LONE:
+		SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_NAT:
+		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+		break;
+#endif /* OTHER_PHY */
+	}
+}	/* SkMacInitPhy */
+
+
+#ifndef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
+ *
+ *	This function analyses the Interrupt status word. If any of the
+ *	Auto-negotiating 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)) != 0) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04x\n",
+			Port, IStatus));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}	/* SkXmAutoNegLipaXmac */
+
+
+/******************************************************************************
+ *
+ *	SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
+ *
+ *	This function analyses the PHY status word.
+ *  If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
+ *	is set true.
+ */
+void SkMacAutoNegLipaPhy(
+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) != 0) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04x\n",
+			Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}	/* SkMacAutoNegLipaPhy */
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneXmac() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * 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 */
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+	if ((LPAb & PHY_X_AN_RFB) != 0) {
+		/* 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) != 0) {
+		/* 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;
+	}
+	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneXmac */
+
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneBcom() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * 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		LPAb;		/* Link Partner Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+#if 0
+01-Sep-2000 RA;:;:
+	SK_U16		ResAb;		/* Resolved Ability */
+#endif	/* 0 */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneBcom, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
+#if 0
+01-Sep-2000 RA;:;:
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+#endif	/* 0 */
+
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+	if ((LPAb & PHY_B_AN_RF) != 0) {
+		/* 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_MSK) == PHY_B_RES_1000FD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == 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);
+	}
+
+#if 0
+01-Sep-2000 RA;:;:
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		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);
+	}
+
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+#endif	/* 0 */
+
+	/* Check PAUSE mismatch */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == 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;
+	}
+	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneBcom */
+
+
+/******************************************************************************
+ *
+ *	SkGmAutoNegDoneMarv() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkGmAutoNegDoneMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		LPAb;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneMarv, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
+
+	if ((LPAb & PHY_M_AN_RF) != 0) {
+		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);
+	}
+
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		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);
+	}
+
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		(SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
+
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
+
+	/* Check Speed & Duplex resolved */
+	if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Speed & Duplex not resolved Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+		return(SK_AND_DUP_CAP);
+	}
+
+	if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	}
+	else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+
+	/* set used link speed */
+	switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
+	case (unsigned)PHY_M_PS_SPEED_1000:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+		break;
+	case PHY_M_PS_SPEED_100:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS;
+		break;
+	default:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS;
+	}
+
+	return(SK_AND_OK);
+}	/* SkGmAutoNegDoneMarv */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneLone() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * 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 */
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+	if ((LPAb & PHY_L_AN_RF) != 0) {
+		/* 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) != 0) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
+	}
+
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_L_1000S_MSF) != 0) {
+		/* 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 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) != 0) {
+			/* 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) != 0) {
+			/* 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);
+	}
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneLone */
+
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneNat() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * 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);
+}	/* SkXmAutoNegDoneNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkMacAutoNegDone() - Auto-negotiation handling
+ *
+ * Description:	calls the auto-negotiation done routines dep. on board type
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+int	SkMacAutoNegDone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int	Rtv;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
+		break;
+	case SK_PHY_BCOM:
+		Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
+		break;
+	case SK_PHY_MARV_COPPER:
+	case SK_PHY_MARV_FIBER:
+		Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
+		break;
+#ifdef OTHER_PHY
+	case SK_PHY_LONE:
+		Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
+		break;
+	case SK_PHY_NAT:
+		Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
+		break;
+#endif /* OTHER_PHY */
+	default:
+		return(SK_AND_OTHER);
+	}
+
+	if (Rtv != SK_AND_OK) {
+		return(Rtv);
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE;
+
+	SkMacRxTxEnable(pAC, IoC, Port);
+
+	return(SK_AND_OK);
+}	/* SkMacAutoNegDone */
+
+
+/******************************************************************************
+ *
+ *	SkXmSetRxTxEn() - Special Set Rx/Tx Enable and some features in XMAC
+ *
+ * Description:
+ *  sets MAC or PHY LoopBack and Duplex Mode in the MMU Command Reg.
+ *  enables Rx/Tx
+ *
+ * Returns: N/A
+ */
+static void SkXmSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)		/* Parameter to set: MAC or PHY LoopBack, Duplex Mode */
+{
+	SK_U16	Word;
+
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
+	case SK_MAC_LOOPB_ON:
+		Word |= XM_MMU_MAC_LB;
+		break;
+	case SK_MAC_LOOPB_OFF:
+		Word &= ~XM_MMU_MAC_LB;
+		break;
+	}
+
+	switch (Para & (SK_PHY_LOOPB_ON | SK_PHY_LOOPB_OFF)) {
+	case SK_PHY_LOOPB_ON:
+		Word |= XM_MMU_GMII_LOOP;
+		break;
+	case SK_PHY_LOOPB_OFF:
+		Word &= ~XM_MMU_GMII_LOOP;
+		break;
+	}
+
+	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
+	case SK_PHY_FULLD_ON:
+		Word |= XM_MMU_GMII_FD;
+		break;
+	case SK_PHY_FULLD_OFF:
+		Word &= ~XM_MMU_GMII_FD;
+		break;
+	}
+
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+
+	/* dummy read to ensure writing */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+}	/* SkXmSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkGmSetRxTxEn() - Special Set Rx/Tx Enable and some features in GMAC
+ *
+ * Description:
+ *  sets MAC LoopBack and Duplex Mode in the General Purpose Control Reg.
+ *  enables Rx/Tx
+ *
+ * Returns: N/A
+ */
+static void SkGmSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)		/* Parameter to set: MAC LoopBack, Duplex Mode */
+{
+	SK_U16	Ctrl;
+
+	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
+
+	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
+	case SK_MAC_LOOPB_ON:
+		Ctrl |= GM_GPCR_LOOP_ENA;
+		break;
+	case SK_MAC_LOOPB_OFF:
+		Ctrl &= ~GM_GPCR_LOOP_ENA;
+		break;
+	}
+
+	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
+	case SK_PHY_FULLD_ON:
+		Ctrl |= GM_GPCR_DUP_FULL;
+		break;
+	case SK_PHY_FULLD_OFF:
+		Ctrl &= ~GM_GPCR_DUP_FULL;
+		break;
+	}
+
+	GM_OUT16(IoC, Port, GM_GP_CTRL, Ctrl | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+
+	/* dummy read to ensure writing */
+	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
+
+}	/* SkGmSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkMacSetRxTxEn() - Special Set Rx/Tx Enable and parameters
+ *
+ * Description:	calls the Special Set Rx/Tx Enable routines dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)
+{
+	if (pAC->GIni.GIGenesis) {
+
+		SkXmSetRxTxEn(pAC, IoC, Port, Para);
+	}
+	else {
+
+		SkGmSetRxTxEn(pAC, IoC, Port, Para);
+	}
+
+}	/* SkMacSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
+ *
+ * Description:	enables Rx/Tx dep. on board type
+ *
+ * Returns:
+ *	0	o.k.
+ *	!= 0	Error happened
+ */
+int SkMacRxTxEnable(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Reg;		/* 16-bit register value */
+	SK_U16		IntMask;	/* MAC interrupt mask */
+	SK_U16		SWord;
+
+	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) {
+		/* Auto-negotiation is not done or failed */
+		return(0);
+	}
+
+	if (pAC->GIni.GIGenesis) {
+		/* set Duplex 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
+		 */
+		IntMask = XM_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overflow */
+		IntMask &= ~XM_IS_RXF_OV;
+#endif /* DEBUG */
+
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			/* disable GP0 interrupt bit */
+			IntMask |= XM_IS_INP_ASS;
+		}
+		XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+
+		/* get MMU Command Reg. */
+		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)) {
+			/* set to Full Duplex */
+			Reg |= XM_MMU_GMII_FD;
+		}
+
+		switch (pPrt->PhyType) {
+		case SK_PHY_BCOM:
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom Phys
+			 * Enable Power Management after link up
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
+			break;
+		case SK_PHY_NAT:
+			/* todo National:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
+			/* no interrupts possible from National ??? */
+			break;
+#endif /* OTHER_PHY */
+		}
+
+		/* enable Rx/Tx */
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+	}
+	else {
+		/*
+		 * Initialize the Interrupt Mask Register. Default IRQs are...
+		 *	- Rx Counter Event Overflow
+		 *	- Tx Counter Event Overflow
+		 *	- Transmit FIFO Underrun
+		 */
+		IntMask = GMAC_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overrun */
+		IntMask |= GM_IS_RX_FF_OR;
+#endif /* DEBUG */
+
+		SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
+
+		/* get General Purpose Control */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
+
+		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+			pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
+			/* set to Full Duplex */
+			Reg |= GM_GPCR_DUP_FULL;
+		}
+
+		/* enable Rx/Tx */
+		GM_OUT16(IoC, Port, GM_GP_CTRL, Reg | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+
+#ifndef VCPU
+		/* Enable all PHY interrupts */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+#endif /* VCPU */
+	}
+
+	return(0);
+
+}	/* SkMacRxTxEnable */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxDisable() - Disable Receiver and Transmitter
+ *
+ * Description:	disables Rx/Tx dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacRxTxDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Word;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+		/* dummy read to ensure writing */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	}
+	else {
+
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+
+		GM_OUT16(IoC, Port, GM_GP_CTRL, Word & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
+
+		/* dummy read to ensure writing */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+	}
+}	/* SkMacRxTxDisable */
+
+
+/******************************************************************************
+ *
+ *	SkMacIrqDisable() - Disable IRQ from MAC
+ *
+ * Description:	sets the IRQ-mask to disable IRQ dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacIrqDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pAC->GIni.GIGenesis) {
+
+		/* disable all XMAC IRQs */
+		XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+
+		/* Disable all PHY interrupts */
+		switch (pPrt->PhyType) {
+			case SK_PHY_BCOM:
+				/* Make sure that PHY is initialized */
+				if (pPrt->PState != SK_PRT_RESET) {
+					/* NOT allowed if BCOM is in RESET state */
+					/* Workaround BCOM Errata (#10523) all BCom */
+					/* Disable Power Management if link is down */
+					SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+						(SK_U16)(Word | PHY_B_AC_DIS_PM));
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+				}
+				break;
+#ifdef OTHER_PHY
+			case SK_PHY_LONE:
+				SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+				break;
+			case SK_PHY_NAT:
+				/* todo: National
+				SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+				break;
+#endif /* OTHER_PHY */
+		}
+	}
+	else {
+		/* disable all GMAC IRQs */
+		SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+
+#ifndef VCPU
+		/* Disable all PHY interrupts */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+#endif /* VCPU */
+	}
+}	/* SkMacIrqDisable */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmSendCont() - Enable / Disable Send Continuous Mode
+ *
+ * Description:	enable / disable Send Continuous Mode on XMAC
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSendCont(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+	if (Enable) {
+		MdReg |= XM_MD_TX_CONT;
+	}
+	else {
+		MdReg &= ~XM_MD_TX_CONT;
+	}
+	/* setup Mode Register */
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+
+}	/* SkXmSendCont*/
+
+/******************************************************************************
+ *
+ *	SkMacTimeStamp() - Enable / Disable Time Stamp
+ *
+ * Description:	enable / disable Time Stamp generation for Rx packets
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacTimeStamp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+	SK_U8	TimeCtrl;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		if (Enable) {
+			MdReg |= XM_MD_ATS;
+		}
+		else {
+			MdReg &= ~XM_MD_ATS;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+		if (Enable) {
+			TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
+		}
+		else {
+			TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
+		}
+		/* Start/Stop Time Stamp Timer */
+		SK_OUT8(pAC, GMAC_TI_ST_CTRL, TimeCtrl);
+	}
+}	/* SkMacTimeStamp*/
+
+#else /* SK_DIAG */
+
+/******************************************************************************
+ *
+ *	SkXmIrq() - Interrupt Service Routine
+ *
+ * Description:	services an Interrupt Request of the XMAC
+ *
+ * Note:
+ *	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_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+	SK_U16		IStatus;	/* Interrupt status read from the XMAC */
+	SK_U16		IStatus2;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	XM_IN16(IoC, Port, XM_ISRC, &IStatus);
+
+	/* LinkPartner Auto-negable? */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+	}
+	else {
+		/* 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);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("XmacIrq Port %d Isr 0x%04x\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_INP_ASS) != 0) {
+		/* Reread ISR Register if link is not in sync */
+		XM_IN16(IoC, Port, XM_ISRC, &IStatus2);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: Link async. Double check Port %d 0x%04x 0x%04x\n",
+			 Port, IStatus, IStatus2));
+		IStatus &= ~XM_IS_INP_ASS;
+		IStatus |= IStatus2;
+	}
+
+	if ((IStatus & XM_IS_LNK_AE) != 0) {
+		/* not used, GP0 is used instead */
+	}
+
+	if ((IStatus & XM_IS_TX_ABORT) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_FRC_INT) != 0) {
+		/* not used, use ASIC IRQ instead if needed */
+	}
+
+	if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
+		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, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+	}
+
+	if ((IStatus & XM_IS_RX_PAGE) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_TX_PAGE) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_AND) != 0) {
+		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) != 0) {
+		/* not used */
+	}
+
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
+		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) != 0) {
+		/* normal situation -> no effect */
+#ifdef DEBUG
+		pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+	}
+
+	if ((IStatus & XM_IS_TXF_UR) != 0) {
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+	}
+
+	if ((IStatus & XM_IS_TX_COMP) != 0) {
+		/* not served here */
+	}
+
+	if ((IStatus & XM_IS_RX_COMP) != 0) {
+		/* not served here */
+	}
+}	/* SkXmIrq */
+
+
+/******************************************************************************
+ *
+ *	SkGmIrq() - Interrupt Service Routine
+ *
+ * Description:	services an Interrupt Request of the GMAC
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+	SK_U8		IStatus;	/* Interrupt status */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
+
+	/* LinkPartner Auto-negable? */
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("GmacIrq Port %d Isr 0x%04x\n", Port, IStatus));
+
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
+		/* these IRQs will be cleared by reading GMACs register */
+		Para.Para32[0] = (SK_U32)Port;
+		Para.Para32[1] = (SK_U32)IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+	}
+
+	if (IStatus & GM_IS_RX_FF_OR) {
+		/* clear GMAC Rx FIFO Overrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
+#ifdef DEBUG
+		pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+	}
+
+	if (IStatus & GM_IS_TX_FF_UR) {
+		/* clear GMAC Tx FIFO Underrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+	}
+
+	if (IStatus & GM_IS_TX_COMPL) {
+		/* not served here */
+	}
+
+	if (IStatus & GM_IS_RX_COMPL) {
+		/* not served here */
+	}
+}	/* SkGmIrq */
+
+/******************************************************************************
+ *
+ *	SkMacIrq() - Interrupt Service Routine for MAC
+ *
+ * Description:	calls the Interrupt Service Routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+
+	if (pAC->GIni.GIGenesis) {
+		/* IRQ from XMAC */
+		SkXmIrq(pAC, IoC, Port);
+	}
+	else {
+		/* IRQ from GMAC */
+		SkGmIrq(pAC, IoC, Port);
+	}
+}	/* SkMacIrq */
+
+#endif /* !SK_DIAG */
+
+/******************************************************************************
+ *
+ *	SkXmUpdateStats() - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values a command must be sent so that the statistic data will
+ *	be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		StatReg;
+	int			WaitIndex;
+
+	pPrt = &pAC->GIni.GP[Port];
+	WaitIndex = 0;
+
+	/* Send an update command to XMAC specified */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+	/*
+	 * It is an auto-clearing register. If the command bits
+	 * went to zero again, the statistics are transferred.
+	 * Normally the command should be executed immediately.
+	 * But just to be sure we execute a loop.
+	 */
+	do {
+
+		XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
+
+		if (++WaitIndex > 10) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);
+
+			return(1);
+		}
+	} while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
+
+	return(0);
+}	/* SkXmUpdateStats */
+
+/******************************************************************************
+ *
+ *	SkGmUpdateStats() - Force the GMAC to output the current statistic
+ *
+ * Description:
+ *	Empty function for GMAC. Statistic data is accessible in direct way.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	return(0);
+}
+
+/******************************************************************************
+ *
+ *	SkXmMacStatistic() - Get XMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmMacStatistic(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,	/* MIB counter base address */
+SK_U32	*pVal)		/* ptr to return statistic value */
+{
+	if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+
+		return(1);
+	}
+
+	XM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkXmMacStatistic */
+
+/******************************************************************************
+ *
+ *	SkGmMacStatistic() - Get GMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmMacStatistic(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,	/* MIB counter base address */
+SK_U32	*pVal)		/* ptr to return statistic value */
+{
+
+	if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
+		return(1);
+	}
+
+	GM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkGmMacStatistic */
+
+/******************************************************************************
+ *
+ *	SkXmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force the XMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+	/* Clear two times according to Errata #3 */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+	return(0);
+}	/* SkXmResetCounter */
+
+/******************************************************************************
+ *
+ *	SkGmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force GMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Reg;	/* Phy Address Register */
+	SK_U16	Word;
+	int		i;
+
+	GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);
+
+#ifndef VCPU
+	/* set MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
+
+	/* read all MIB Counters with Clear Mode set */
+	for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
+		/* the reset is performed only when the lower 16 bits are read */
+		GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
+	}
+
+	/* clear MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
+#endif /* !VCPU */
+
+	return(0);
+}	/* SkGmResetCounter */
+
+/******************************************************************************
+ *
+ *	SkXmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	upper dword stores the XMAC ReceiveCounterEvent register and the lower
+ *	dword the XMAC TransmitCounterEvent register.
+ *
+ * Note:
+ *	For XMAC the interrupt source is a self-clearing register, so the source
+ *	must be checked only once. SIRQ module does another check to be sure
+ *	that no interrupt get lost during process time.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmOverflowStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16  IStatus,	/* Interupt Status from MAC */
+SK_U64	*pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;	/* Overflow status */
+	SK_U32	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & XM_IS_RXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+
+	if ((IStatus & XM_IS_TXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkXmOverflowStatus */
+
+
+/******************************************************************************
+ *
+ *	SkGmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	the following bit coding is used:
+ *	63:56 - unused
+ *	55:48 - TxRx interrupt register bit7:0
+ *	32:47 - Rx interrupt register
+ *	31:24 - unused
+ *	23:16 - TxRx interrupt register bit15:8
+ *	15:0  - Tx interrupt register
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmOverflowStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16  IStatus,	/* Interupt Status from MAC */
+SK_U64	*pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;		/* Overflow status */
+	SK_U16	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & GM_IS_RX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+
+	if ((IStatus & GM_IS_TX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+
+	/* this register is self-clearing after read */
+	GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
+	/* Rx overflow interrupt register bits (LoByte)*/
+	Status |= (SK_U64)((SK_U8)RegVal) << 48;
+	/* Tx overflow interrupt register bits (HiByte)*/
+	Status |= (SK_U64)(RegVal >> 8) << 16;
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkGmOverflowStatus */
+
+/******************************************************************************
+ *
+ *	SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
+ *
+ * Description:
+ *  starts the cable diagnostic test if 'StartTest' is true
+ *  gets the results if 'StartTest' is true
+ *
+ * NOTE:	this test is meaningful only when link is down
+ *
+ * Returns:
+ *	0:  success
+ *	1:	no YUKON copper
+ *	2:	test in progress
+ */
+int SkGmCableDiagStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,   		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	StartTest)	/* flag for start / get result */
+{
+	int		i;
+	SK_U16	RegVal;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+
+		return(1);
+	}
+
+	if (StartTest) {
+		/* only start the cable test */
+		if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
+			/* apply TDR workaround from Marvell */
+			SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
+
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
+		}
+
+		/* set address to 0 for MDI[0] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);
+
+		/* Read Cable Diagnostic Reg */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		/* start Cable Diagnostic Test */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
+			(SK_U16)(RegVal | PHY_M_CABD_ENA_TEST));
+
+		return(0);
+	}
+
+	/* Read Cable Diagnostic Reg */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Cable Diag.=0x%04X\n", RegVal));
+
+	if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
+		/* test is running */
+		return(2);
+	}
+
+	/* get the test results */
+	for (i = 0; i < 4; i++)  {
+		/* set address to i for MDI[i] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);
+
+		/* get Cable Diagnostic values */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);
+
+		pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
+	}
+
+	return(0);
+}	/* SkGmCableDiagStatus */
+
+#endif /* CONFIG_SK98 */
+
+/* End of file */
diff --git a/drivers/net/sk98lin/u-boot_compat.h b/drivers/net/sk98lin/u-boot_compat.h
new file mode 100644
index 0000000..1e385f8
--- /dev/null
+++ b/drivers/net/sk98lin/u-boot_compat.h
@@ -0,0 +1,98 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _UBOOT_COMPAT_H__
+#define _UBOOT_COMPAT_H__
+
+
+#include <pci.h>
+#include <pci_ids.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+
+#define	__initdata
+#define __init
+#define __exit
+
+#define netif_stop_queue(x)
+#define netif_wake_queue(x)
+#define netif_running(x)		0
+#define unregister_netdev(x)
+#define remove_proc_entry(x,y)
+
+#define dev_addr			enetaddr
+
+#define	spin_lock_irqsave(x,y) y = 0;
+#define spin_lock_init(x)
+#define spin_lock(x)
+#define spin_unlock_irqrestore(x,y)
+#define spin_unlock(x)
+
+
+#define ENODEV				1
+#define EAGAIN				2
+#define EBUSY				3
+
+#define HZ				CFG_HZ
+
+
+#define printk				printf
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_INFO
+
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+
+
+#define kmalloc(x,y)			malloc(x)
+#define kfree(x)			free(x)
+#define GFP_ATOMIC			0
+
+#define pci_alloc_consistent(x,y,z)	(void *)(*(dma_addr_t *)(z) = (dma_addr_t)malloc(y))
+#define pci_free_consistent(x,y,z,d)	free(z)
+#define pci_dma_sync_single(x,y,z,d)
+#define pci_unmap_page(x,y,z,d)
+#define pci_unmap_single(x,y,z,d)
+#define pci_present()			1
+
+struct sk_buff
+{
+	u8 * data;
+	u32 len;
+	u8 * data_unaligned;
+};
+
+struct sk_buff * alloc_skb(u32 size, int dummy);
+void dev_kfree_skb_any(struct sk_buff *skb);
+void skb_reserve(struct sk_buff *skb, unsigned int len);
+void skb_put(struct sk_buff *skb, unsigned int len);
+
+#define dev_kfree_skb				dev_kfree_skb_any
+#define dev_kfree_skb_irq			dev_kfree_skb_any
+
+#define eth_copy_and_sum(dest,src,len,base)	memcpy(dest->data,src,len);
+
+
+#endif	/* _UBOOT_COMPAT_H__ */
diff --git a/drivers/net/sk98lin/uboot_drv.c b/drivers/net/sk98lin/uboot_drv.c
new file mode 100644
index 0000000..d02cd1b
--- /dev/null
+++ b/drivers/net/sk98lin/uboot_drv.c
@@ -0,0 +1,143 @@
+/*
+ * Driver for SysKonnect Gigabit Ethernet Server Adapters.
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+	defined(CONFIG_SK98)
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#include "u-boot_compat.h"
+
+
+#define SKGE_MAX_CARDS	2
+
+
+extern int skge_probe(struct eth_device **);
+extern void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
+extern void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
+extern int SkGeOpen(struct eth_device *);
+extern int SkGeClose(struct eth_device *);
+extern int SkGeXmit(struct sk_buff *skb, struct eth_device *dev);
+extern void ReceiveIrq(SK_AC *pAC, RX_PORT *pRxPort, SK_BOOL SlowPathLock);
+
+static int skge_init(struct eth_device *dev, bd_t * bis);
+static int skge_send(struct eth_device *dev, volatile void *packet, int length);
+static int skge_recv(struct eth_device *dev);
+static void skge_halt(struct eth_device *dev);
+
+int skge_initialize(bd_t * bis)
+{
+	int numdev, i;
+	struct eth_device *dev[SKGE_MAX_CARDS];
+
+	numdev = skge_probe(&dev[0]);
+
+	if (numdev > SKGE_MAX_CARDS)
+	{
+		printf("ERROR: numdev > SKGE_MAX_CARDS\n");
+	}
+
+	for (i = 0; i < numdev; i++)
+	{
+		sprintf (dev[i]->name, "SK98#%d", i);
+
+		dev[i]->init = skge_init;
+		dev[i]->halt = skge_halt;
+		dev[i]->send = skge_send;
+		dev[i]->recv = skge_recv;
+
+		eth_register(dev[i]);
+	}
+
+	return numdev;
+}
+
+
+static int skge_init(struct eth_device *dev, bd_t * bis)
+{
+	int ret;
+	SK_AC * pAC = ((DEV_NET*)dev->priv)->pAC;
+	int i;
+
+	ret = SkGeOpen(dev);
+
+	while (pAC->Rlmt.Port[0].PortState != SK_RLMT_PS_GOING_UP)
+	{
+		SkGeIsrOnePort (0, pAC->dev[0], 0);
+	}
+
+	for (i = 0; i < 100; i ++)
+	{
+		udelay(1000);
+	}
+
+	return ret;
+}
+
+
+static void skge_halt(struct eth_device *dev)
+{
+	SkGeClose(dev);
+}
+
+
+static int skge_send(struct eth_device *dev, volatile void *packet,
+						  int length)
+{
+	int ret = -1;
+	struct sk_buff * skb = alloc_skb(length, 0);
+
+	if (! skb)
+	{
+		printf("skge_send: failed to alloc skb\n");
+		goto Done;
+	}
+
+	memcpy(skb->data, (void*)packet, length);
+	ret = SkGeXmit(skb, dev);
+
+Done:
+	return ret;
+}
+
+
+static int skge_recv(struct eth_device *dev)
+{
+	DEV_NET		*pNet;
+	SK_AC		*pAC;
+	int		FromPort = 0;
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
+
+	return 0;
+}
+
+
+#endif	/* CONFIG_SK98 */
diff --git a/drivers/net/sk98lin/uboot_skb.c b/drivers/net/sk98lin/uboot_skb.c
new file mode 100644
index 0000000..3a487a8
--- /dev/null
+++ b/drivers/net/sk98lin/uboot_skb.c
@@ -0,0 +1,122 @@
+/*
+ * Definitions for the 'struct sk_buff' memory handlers in U-Boot.
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef CONFIG_SK98
+
+#include <common.h>
+#include "u-boot_compat.h"
+
+#define MAX_SKB		50
+
+static struct sk_buff *sk_table[MAX_SKB];
+
+
+struct sk_buff * alloc_skb(u32 size, int dummy)
+{
+	int i;
+	struct sk_buff * ret = NULL;
+
+	for (i = 0; i < MAX_SKB; i++)
+	{
+		if (sk_table[i])
+		{
+				/* Already allocated.
+				 */
+			continue;
+		}
+
+		sk_table[i] = malloc(sizeof(struct sk_buff));
+		if (! sk_table[i])
+		{
+			printf("alloc_skb: malloc failed\n");
+			break;
+		}
+
+		memset(sk_table[i], 0, sizeof(struct sk_buff));
+		sk_table[i]->data = sk_table[i]->data_unaligned =
+		                                            malloc(size + 16);
+		if (! sk_table[i]->data)
+		{
+			printf("alloc_skb: malloc failed\n");
+			free(sk_table[i]);
+			sk_table[i] = NULL;
+			break;
+		}
+
+		sk_table[i]->data += 16 - ((u32)sk_table[i]->data & 15);
+		sk_table[i]->len = size;
+
+		break;
+	}
+
+	if (i < MAX_SKB)
+	{
+		ret = sk_table[i];
+	}
+
+	if (! ret)
+	{
+		printf("Unable to allocate skb!\n");
+	}
+
+	return ret;
+}
+
+void dev_kfree_skb_any(struct sk_buff *skb)
+{
+	int i;
+
+	for (i = 0; i < MAX_SKB; i++)
+	{
+		if (sk_table[i] != skb)
+		{
+			continue;
+		}
+
+		free(skb->data_unaligned);
+		free(skb);
+		sk_table[i] = NULL;
+		break;
+	}
+
+	if (i == MAX_SKB)
+	{
+		printf("SKB allocation error!\n");
+	}
+}
+
+void skb_reserve(struct sk_buff *skb, unsigned int len)
+{
+	skb->data+=len;
+}
+
+void skb_put(struct sk_buff *skb, unsigned int len)
+{
+	skb->len+=len;
+}
+
+#endif /* CONFIG_SK98 */
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
new file mode 100644
index 0000000..8061f12
--- /dev/null
+++ b/drivers/net/smc91111.c
@@ -0,0 +1,1623 @@
+/*------------------------------------------------------------------------
+ . smc91111.c
+ . This is a driver for SMSC's 91C111 single-chip Ethernet device.
+ .
+ . (C) Copyright 2002
+ . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ . Rolf Offermanns <rof@sysgo.de>
+ .
+ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ .	 Developed by Simple Network Magic Corporation (SNMC)
+ . Copyright (C) 1996 by Erik Stahlman (ES)
+ .
+ . 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.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ .
+ . "Features" of the SMC chip:
+ .   Integrated PHY/MAC for 10/100BaseT Operation
+ .   Supports internal and external MII
+ .   Integrated 8K packet memory
+ .   EEPROM interface for configuration
+ .
+ . Arguments:
+ .	io	= for the base address
+ .	irq	= for the IRQ
+ .
+ . author:
+ .	Erik Stahlman				( erik@vt.edu )
+ .	Daris A Nevil				( dnevil@snmc.com )
+ .
+ .
+ . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ .
+ . Sources:
+ .    o	  SMSC LAN91C111 databook (www.smsc.com)
+ .    o	  smc9194.c by Erik Stahlman
+ .    o	  skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
+ .
+ . History:
+ .	06/19/03  Richard Woodruff Made u-boot environment aware and added mac addr checks.
+ .	10/17/01  Marco Hasewinkel Modify for DNP/1110
+ .	07/25/01  Woojung Huh	   Modify for ADS Bitsy
+ .	04/25/01  Daris A Nevil	   Initial public release through SMSC
+ .	03/16/01  Daris A Nevil	   Modified smc9194.c for use with LAN91C111
+ ----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include "smc91111.h"
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_SMC91111
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN	0
+
+#define NO_AUTOPROBE
+
+#define SMC_DEBUG 0
+
+#if SMC_DEBUG > 1
+static const char version[] =
+	"smc91111.c:v1.0 04/25/01 by Daris A Nevil (dnevil@snmc.com)\n";
+#endif
+
+/* Autonegotiation timeout in seconds */
+#ifndef CONFIG_SMC_AUTONEG_TIMEOUT
+#define CONFIG_SMC_AUTONEG_TIMEOUT 10
+#endif
+
+/*------------------------------------------------------------------------
+ .
+ . Configuration options, for the experienced user to change.
+ .
+ -------------------------------------------------------------------------*/
+
+/*
+ . Wait time for memory to be free.  This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver.	 If you are changing anything
+ . here with the SMC stuff, you should have the datasheet and know
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+#define CARDNAME "LAN91C111"
+
+/* Memory sizing constant */
+#define LAN91C111_MEMORY_MULTIPLIER	(1024*2)
+
+#ifndef CONFIG_SMC91111_BASE
+#define CONFIG_SMC91111_BASE 0x20000300
+#endif
+
+#define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE
+
+#define SMC_DEV_NAME "SMC91111"
+#define SMC_PHY_ADDR 0x0000
+#define SMC_ALLOC_MAX_TRY 5
+#define SMC_TX_TIMEOUT 30
+
+#define SMC_PHY_CLOCK_DELAY 1000
+
+#define ETH_ZLEN 60
+
+#ifdef	CONFIG_SMC_USE_32_BIT
+#define USE_32_BIT  1
+#else
+#undef USE_32_BIT
+#endif
+/*-----------------------------------------------------------------
+ .
+ .  The driver can be entered at any of the following entry points.
+ .
+ .------------------------------------------------------------------  */
+
+extern int eth_init(bd_t *bd);
+extern void eth_halt(void);
+extern int eth_rx(void);
+extern int eth_send(volatile void *packet, int length);
+
+#ifdef SHARED_RESOURCES
+	extern void swap_to(int device_id);
+#endif
+
+/*
+ . This is called by  register_netdev().  It is responsible for
+ . checking the portlist for the SMC9000 series chipset.  If it finds
+ . one, then it will initialize the device, find the hardware information,
+ . and sets up the appropriate device parameters.
+ . NOTE: Interrupts are *OFF* when this procedure is called.
+ .
+ . NB:This shouldn't be static since it is referred to externally.
+*/
+int smc_init(void);
+
+/*
+ . This is called by  unregister_netdev().  It is responsible for
+ . cleaning up before the driver is finally unregistered and discarded.
+*/
+void smc_destructor(void);
+
+/*
+ . The kernel calls this function when someone wants to use the device,
+ . typically 'ifconfig ethX up'.
+*/
+static int smc_open(bd_t *bd);
+
+
+/*
+ . This is called by the kernel in response to 'ifconfig ethX down'.  It
+ . is responsible for cleaning up everything that the open routine
+ . does, and maybe putting the card into a powerdown state.
+*/
+static int smc_close(void);
+
+/*
+ . Configures the PHY through the MII Management interface
+*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static void smc_phy_configure(void);
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+/*
+ . This is a separate procedure to handle the receipt of a packet, to
+ . leave the interrupt code looking slightly cleaner
+*/
+static int smc_rcv(void);
+
+/* See if a MAC address is defined in the current environment. If so use it. If not
+ . print a warning and set the environment and other globals with the default.
+ . If an EEPROM is present it really should be consulted.
+*/
+int smc_get_ethaddr(bd_t *bd);
+int get_rom_mac(uchar *v_rom_mac);
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+#ifdef CONFIG_SMC_USE_IOFUNCS
+/*
+ * input and output functions
+ *
+ * Implemented due to inx,outx macros accessing the device improperly
+ * and putting the device into an unkown state.
+ *
+ * For instance, on Sharp LPD7A400 SDK, affects were chip memory
+ * could not be free'd (hence the alloc failures), duplicate packets,
+ * packets being corrupt (shifted) on the wire, etc.  Switching to the
+ * inx,outx functions fixed this problem.
+ */
+static inline word SMC_inw(dword offset);
+static inline void SMC_outw(word value, dword offset);
+static inline byte SMC_inb(dword offset);
+static inline void SMC_outb(byte value, dword offset);
+static inline void SMC_insw(dword offset, volatile uchar* buf, dword len);
+static inline void SMC_outsw(dword offset, uchar* buf, dword len);
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+static inline word SMC_inw(dword offset)
+{
+	word v;
+	v = *((volatile word*)(SMC_BASE_ADDRESS+offset));
+	barrier(); *(volatile u32*)(0xc0000000);
+	return v;
+}
+
+static inline void SMC_outw(word value, dword offset)
+{
+	*((volatile word*)(SMC_BASE_ADDRESS+offset)) = value;
+	barrier(); *(volatile u32*)(0xc0000000);
+}
+
+static inline byte SMC_inb(dword offset)
+{
+	word  _w;
+
+	_w = SMC_inw(offset & ~((dword)1));
+	return (offset & 1) ? (byte)(_w >> 8) : (byte)(_w);
+}
+
+static inline void SMC_outb(byte value, dword offset)
+{
+	word  _w;
+
+	_w = SMC_inw(offset & ~((dword)1));
+	if (offset & 1)
+			*((volatile word*)(SMC_BASE_ADDRESS+(offset & ~((dword)1)))) = (value<<8) | (_w & 0x00ff);
+	else
+			*((volatile word*)(SMC_BASE_ADDRESS+offset)) = value | (_w & 0xff00);
+}
+
+static inline void SMC_insw(dword offset, volatile uchar* buf, dword len)
+{
+	volatile word *p = (volatile word *)buf;
+
+	while (len-- > 0) {
+		*p++ = SMC_inw(offset);
+		barrier();
+		*((volatile u32*)(0xc0000000));
+	}
+}
+
+static inline void SMC_outsw(dword offset, uchar* buf, dword len)
+{
+	volatile word *p = (volatile word *)buf;
+
+	while (len-- > 0) {
+		SMC_outw(*p++, offset);
+		barrier();
+		*(volatile u32*)(0xc0000000);
+	}
+}
+#endif  /* CONFIG_SMC_USE_IOFUNCS */
+
+static char unsigned smc_mac_addr[6] = {0x02, 0x80, 0xad, 0x20, 0x31, 0xb8};
+
+/*
+ * This function must be called before smc_open() if you want to override
+ * the default mac address.
+ */
+
+void smc_set_mac_addr(const unsigned char *addr) {
+	int i;
+
+	for (i=0; i < sizeof(smc_mac_addr); i++){
+		smc_mac_addr[i] = addr[i];
+	}
+}
+
+/*
+ * smc_get_macaddr is no longer used. If you want to override the default
+ * mac address, call smc_get_mac_addr as a part of the board initialization.
+ */
+
+#if 0
+void smc_get_macaddr( byte *addr ) {
+	/* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */
+	unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
+	int i;
+
+
+	for (i=0; i<6; i++) {
+	    addr[0] = *(dnp1110_mac+0);
+	    addr[1] = *(dnp1110_mac+1);
+	    addr[2] = *(dnp1110_mac+2);
+	    addr[3] = *(dnp1110_mac+3);
+	    addr[4] = *(dnp1110_mac+4);
+	    addr[5] = *(dnp1110_mac+5);
+	}
+}
+#endif /* 0 */
+
+/***********************************************
+ * Show available memory		       *
+ ***********************************************/
+void dump_memory_info(void)
+{
+	word mem_info;
+	word old_bank;
+
+	old_bank = SMC_inw(BANK_SELECT)&0xF;
+
+	SMC_SELECT_BANK(0);
+	mem_info = SMC_inw( MIR_REG );
+	PRINTK2("Memory: %4d available\n", (mem_info >> 8)*2048);
+
+	SMC_SELECT_BANK(old_bank);
+}
+/*
+ . A rather simple routine to print out a packet for debugging purposes.
+*/
+#if SMC_DEBUG > 2
+static void print_packet( byte *, int );
+#endif
+
+#define tx_done(dev) 1
+
+
+/* this does a soft reset on the device */
+static void smc_reset( void );
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable( void );
+
+/* this puts the device in an inactive state */
+static void smc_shutdown( void );
+
+/* Routines to Read and Write the PHY Registers across the
+   MII Management Interface
+*/
+
+#ifndef CONFIG_SMC91111_EXT_PHY
+static word smc_read_phy_register(byte phyreg);
+static void smc_write_phy_register(byte phyreg, word phydata);
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+static int poll4int (byte mask, int timeout)
+{
+	int tmo = get_timer (0) + timeout * CFG_HZ;
+	int is_timeout = 0;
+	word old_bank = SMC_inw (BSR_REG);
+
+	PRINTK2 ("Polling...\n");
+	SMC_SELECT_BANK (2);
+	while ((SMC_inw (SMC91111_INT_REG) & mask) == 0) {
+		if (get_timer (0) >= tmo) {
+			is_timeout = 1;
+			break;
+		}
+	}
+
+	/* restore old bank selection */
+	SMC_SELECT_BANK (old_bank);
+
+	if (is_timeout)
+		return 1;
+	else
+		return 0;
+}
+
+/* Only one release command at a time, please */
+static inline void smc_wait_mmu_release_complete (void)
+{
+	int count = 0;
+
+	/* assume bank 2 selected */
+	while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
+		udelay (1);	/* Wait until not busy */
+		if (++count > 200)
+			break;
+	}
+}
+
+/*
+ . Function: smc_reset( void )
+ . Purpose:
+ .	This sets the SMC91111 chip to its normal state, hopefully from whatever
+ .	mess that any other DOS driver has put it in.
+ .
+ . Maybe I should reset more registers to defaults in here?  SOFTRST  should
+ . do that for me.
+ .
+ . Method:
+ .	1.  send a SOFT RESET
+ .	2.  wait for it to finish
+ .	3.  enable autorelease mode
+ .	4.  reset the memory management unit
+ .	5.  clear all interrupts
+ .
+*/
+static void smc_reset (void)
+{
+	PRINTK2 ("%s: smc_reset\n", SMC_DEV_NAME);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK (0);
+	SMC_outw (RCR_SOFTRST, RCR_REG);
+
+	/* Setup the Configuration Register */
+	/* This is necessary because the CONFIG_REG is not affected */
+	/* by a soft reset */
+
+	SMC_SELECT_BANK (1);
+#if defined(CONFIG_SMC91111_EXT_PHY)
+	SMC_outw (CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG);
+#else
+	SMC_outw (CONFIG_DEFAULT, CONFIG_REG);
+#endif
+
+
+	/* Release from possible power-down state */
+	/* Configuration register is not affected by Soft Reset */
+	SMC_outw (SMC_inw (CONFIG_REG) | CONFIG_EPH_POWER_EN, CONFIG_REG);
+
+	SMC_SELECT_BANK (0);
+
+	/* this should pause enough for the chip to be happy */
+	udelay (10);
+
+	/* Disable transmit and receive functionality */
+	SMC_outw (RCR_CLEAR, RCR_REG);
+	SMC_outw (TCR_CLEAR, TCR_REG);
+
+	/* set the control register */
+	SMC_SELECT_BANK (1);
+	SMC_outw (CTL_DEFAULT, CTL_REG);
+
+	/* Reset the MMU */
+	SMC_SELECT_BANK (2);
+	smc_wait_mmu_release_complete ();
+	SMC_outw (MC_RESET, MMU_CMD_REG);
+	while (SMC_inw (MMU_CMD_REG) & MC_BUSY)
+		udelay (1);	/* Wait until not busy */
+
+	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+	   but this is a place where future chipsets _COULD_ break.  Be wary
+	   of issuing another MMU command right after this */
+
+	/* Disable all interrupts */
+	SMC_outb (0, IM_REG);
+}
+
+/*
+ . Function: smc_enable
+ . Purpose: let the chip talk to the outside work
+ . Method:
+ .	1.  Enable the transmitter
+ .	2.  Enable the receiver
+ .	3.  Enable interrupts
+*/
+static void smc_enable()
+{
+	PRINTK2("%s: smc_enable\n", SMC_DEV_NAME);
+	SMC_SELECT_BANK( 0 );
+	/* see the header file for options in TCR/RCR DEFAULT*/
+	SMC_outw( TCR_DEFAULT, TCR_REG );
+	SMC_outw( RCR_DEFAULT, RCR_REG );
+
+	/* clear MII_DIS */
+/*	smc_write_phy_register(PHY_CNTL_REG, 0x0000); */
+}
+
+/*
+ . Function: smc_shutdown
+ . Purpose:  closes down the SMC91xxx chip.
+ . Method:
+ .	1. zero the interrupt mask
+ .	2. clear the enable receive flag
+ .	3. clear the enable xmit flags
+ .
+ . TODO:
+ .   (1) maybe utilize power down mode.
+ .	Why not yet?  Because while the chip will go into power down mode,
+ .	the manual says that it will wake up in response to any I/O requests
+ .	in the register space.	 Empirical results do not show this working.
+*/
+static void smc_shutdown()
+{
+	PRINTK2(CARDNAME ": smc_shutdown\n");
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK( 2 );
+	SMC_outb( 0, IM_REG );
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK( 0 );
+	SMC_outb( RCR_CLEAR, RCR_REG );
+	SMC_outb( TCR_CLEAR, TCR_REG );
+#ifdef SHARED_RESOURCES
+	swap_to(FLASH);
+#endif
+}
+
+
+/*
+ . Function:  smc_hardware_send_packet(struct net_device * )
+ . Purpose:
+ .	This sends the actual packet to the SMC9xxx chip.
+ .
+ . Algorithm:
+ .	First, see if a saved_skb is available.
+ .		( this should NOT be called if there is no 'saved_skb'
+ .	Now, find the packet number that the chip allocated
+ .	Point the data pointers at it in memory
+ .	Set the length word in the chip's memory
+ .	Dump the packet to chip memory
+ .	Check if a last byte is needed ( odd length packet )
+ .		if so, set the control flag right
+ .	Tell the card to send it
+ .	Enable the transmit interrupt, so I know if it failed
+ .	Free the kernel data if I actually sent it.
+*/
+static int smc_send_packet (volatile void *packet, int packet_length)
+{
+	byte packet_no;
+	unsigned long ioaddr;
+	byte *buf;
+	int length;
+	int numPages;
+	int try = 0;
+	int time_out;
+	byte status;
+	byte saved_pnr;
+	word saved_ptr;
+
+	/* save PTR and PNR registers before manipulation */
+	SMC_SELECT_BANK (2);
+	saved_pnr = SMC_inb( PN_REG );
+	saved_ptr = SMC_inw( PTR_REG );
+
+	PRINTK3 ("%s: smc_hardware_send_packet\n", SMC_DEV_NAME);
+
+	length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
+
+	/* allocate memory
+	 ** The MMU wants the number of pages to be the number of 256 bytes
+	 ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	 **
+	 ** The 91C111 ignores the size bits, but the code is left intact
+	 ** for backwards and future compatibility.
+	 **
+	 ** Pkt size for allocating is data length +6 (for additional status
+	 ** words, length and ctl!)
+	 **
+	 ** If odd size then last byte is included in this header.
+	 */
+	numPages = ((length & 0xfffe) + 6);
+	numPages >>= 8;		/* Divide by 256 */
+
+	if (numPages > 7) {
+		printf ("%s: Far too big packet error. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* now, try to allocate the memory */
+	SMC_SELECT_BANK (2);
+	SMC_outw (MC_ALLOC | numPages, MMU_CMD_REG);
+
+	/* FIXME: the ALLOC_INT bit never gets set *
+	 * so the following will always give a	   *
+	 * memory allocation error.		   *
+	 * same code works in armboot though	   *
+	 * -ro
+	 */
+
+again:
+	try++;
+	time_out = MEMORY_WAIT_TIME;
+	do {
+		status = SMC_inb (SMC91111_INT_REG);
+		if (status & IM_ALLOC_INT) {
+			/* acknowledge the interrupt */
+			SMC_outb (IM_ALLOC_INT, SMC91111_INT_REG);
+			break;
+		}
+	} while (--time_out);
+
+	if (!time_out) {
+		PRINTK2 ("%s: memory allocation, try %d failed ...\n",
+			 SMC_DEV_NAME, try);
+		if (try < SMC_ALLOC_MAX_TRY)
+			goto again;
+		else
+			return 0;
+	}
+
+	PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
+		 SMC_DEV_NAME, try);
+
+	/* I can send the packet now.. */
+
+	ioaddr = SMC_BASE_ADDRESS;
+
+	buf = (byte *) packet;
+
+	/* If I get here, I _know_ there is a packet slot waiting for me */
+	packet_no = SMC_inb (AR_REG);
+	if (packet_no & AR_FAILED) {
+		/* or isn't there?  BAD CHIP! */
+		printf ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* we have a packet address, so tell the card to use it */
+#ifndef CONFIG_XAENIAX
+	SMC_outb (packet_no, PN_REG);
+#else
+	/* On Xaeniax board, we can't use SMC_outb here because that way
+	 * the Allocate MMU command will end up written to the command register
+	 * as well, which will lead to a problem.
+	 */
+	SMC_outl (packet_no << 16, 0);
+#endif
+	/* do not write new ptr value if Write data fifo not empty */
+	while ( saved_ptr & PTR_NOTEMPTY )
+		printf ("Write data fifo not empty!\n");
+
+	/* point to the beginning of the packet */
+	SMC_outw (PTR_AUTOINC, PTR_REG);
+
+	PRINTK3 ("%s: Trying to xmit packet of length %x\n",
+		 SMC_DEV_NAME, length);
+
+#if SMC_DEBUG > 2
+	printf ("Transmitting Packet\n");
+	print_packet (buf, length);
+#endif
+
+	/* send the packet length ( +6 for status, length and ctl byte )
+	   and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+	SMC_outl ((length + 6) << 16, SMC91111_DATA_REG);
+#else
+	SMC_outw (0, SMC91111_DATA_REG);
+	/* send the packet length ( +6 for status words, length, and ctl */
+	SMC_outw ((length + 6), SMC91111_DATA_REG);
+#endif
+
+	/* send the actual data
+	   . I _think_ it's faster to send the longs first, and then
+	   . mop up by sending the last word.  It depends heavily
+	   . on alignment, at least on the 486.	 Maybe it would be
+	   . a good idea to check which is optimal?  But that could take
+	   . almost as much time as is saved?
+	 */
+#ifdef USE_32_BIT
+	SMC_outsl (SMC91111_DATA_REG, buf, length >> 2);
+#ifndef CONFIG_XAENIAX
+	if (length & 0x2)
+		SMC_outw (*((word *) (buf + (length & 0xFFFFFFFC))),
+			  SMC91111_DATA_REG);
+#else
+	/* On XANEIAX, we can only use 32-bit writes, so we need to handle
+	 * unaligned tail part specially. The standard code doesn't work.
+	 */
+	if ((length & 3) == 3) {
+		u16 * ptr = (u16*) &buf[length-3];
+		SMC_outl((*ptr) | ((0x2000 | buf[length-1]) << 16),
+				SMC91111_DATA_REG);
+	} else if ((length & 2) == 2) {
+		u16 * ptr = (u16*) &buf[length-2];
+		SMC_outl(*ptr, SMC91111_DATA_REG);
+	} else if (length & 1) {
+		SMC_outl((0x2000 | buf[length-1]), SMC91111_DATA_REG);
+	} else {
+		SMC_outl(0, SMC91111_DATA_REG);
+	}
+#endif
+#else
+	SMC_outsw (SMC91111_DATA_REG, buf, (length) >> 1);
+#endif /* USE_32_BIT */
+
+#ifndef CONFIG_XAENIAX
+	/* Send the last byte, if there is one.	  */
+	if ((length & 1) == 0) {
+		SMC_outw (0, SMC91111_DATA_REG);
+	} else {
+		SMC_outw (buf[length - 1] | 0x2000, SMC91111_DATA_REG);
+	}
+#endif
+
+	/* and let the chipset deal with it */
+	SMC_outw (MC_ENQUEUE, MMU_CMD_REG);
+
+	/* poll for TX INT */
+	/* if (poll4int (IM_TX_INT, SMC_TX_TIMEOUT)) { */
+	/* poll for TX_EMPTY INT - autorelease enabled */
+	if (poll4int(IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) {
+		/* sending failed */
+		PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
+
+		/* release packet */
+		/* no need to release, MMU does that now */
+#ifdef CONFIG_XAENIAX
+		 SMC_outw (MC_FREEPKT, MMU_CMD_REG);
+#endif
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+
+
+		return 0;
+	} else {
+		/* ack. int */
+		SMC_outb (IM_TX_EMPTY_INT, SMC91111_INT_REG);
+		/* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */
+		PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME,
+			 length);
+
+		/* release packet */
+		/* no need to release, MMU does that now */
+#ifdef CONFIG_XAENIAX
+		SMC_outw (MC_FREEPKT, MMU_CMD_REG);
+#endif
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+
+
+	}
+
+	/* restore previously saved registers */
+#ifndef CONFIG_XAENIAX
+	SMC_outb( saved_pnr, PN_REG );
+#else
+	/* On Xaeniax board, we can't use SMC_outb here because that way
+	 * the Allocate MMU command will end up written to the command register
+	 * as well, which will lead to a problem.
+	 */
+	SMC_outl(saved_pnr << 16, 0);
+#endif
+	SMC_outw( saved_ptr, PTR_REG );
+
+	return length;
+}
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_destructor( struct net_device * dev )
+ |   Input parameters:
+ |	dev, pointer to the device structure
+ |
+ |   Output:
+ |	None.
+ |
+ ---------------------------------------------------------------------------
+*/
+void smc_destructor()
+{
+	PRINTK2(CARDNAME ": smc_destructor\n");
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open (bd_t * bd)
+{
+	int i, err;
+
+	PRINTK2 ("%s: smc_open\n", SMC_DEV_NAME);
+
+	/* reset the hardware */
+	smc_reset ();
+	smc_enable ();
+
+	/* Configure the PHY */
+#ifndef CONFIG_SMC91111_EXT_PHY
+	smc_phy_configure ();
+#endif
+
+	/* conservative setting (10Mbps, HalfDuplex, no AutoNeg.) */
+/*	SMC_SELECT_BANK(0); */
+/*	SMC_outw(0, RPC_REG); */
+	SMC_SELECT_BANK (1);
+
+	err = smc_get_ethaddr (bd);	/* set smc_mac_addr, and sync it with u-boot globals */
+	if (err < 0) {
+		memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
+		return (-1);	/* upper code ignores this, but NOT bi_enetaddr */
+	}
+#ifdef USE_32_BIT
+	for (i = 0; i < 6; i += 2) {
+		word address;
+
+		address = smc_mac_addr[i + 1] << 8;
+		address |= smc_mac_addr[i];
+		SMC_outw (address, (ADDR0_REG + i));
+	}
+#else
+	for (i = 0; i < 6; i++)
+		SMC_outb (smc_mac_addr[i], (ADDR0_REG + i));
+#endif
+
+	return 0;
+}
+
+/*-------------------------------------------------------------
+ .
+ . smc_rcv -  receive a packet from the card
+ .
+ . There is ( at least ) a packet waiting to be read from
+ . chip-memory.
+ .
+ . o Read the status
+ . o If an error, record it
+ . o otherwise, read in the packet
+ --------------------------------------------------------------
+*/
+static int smc_rcv()
+{
+	int	packet_number;
+	word	status;
+	word	packet_length;
+	int	is_error = 0;
+#ifdef USE_32_BIT
+	dword stat_len;
+#endif
+	byte saved_pnr;
+	word saved_ptr;
+
+	SMC_SELECT_BANK(2);
+	/* save PTR and PTR registers */
+	saved_pnr = SMC_inb( PN_REG );
+	saved_ptr = SMC_inw( PTR_REG );
+
+	packet_number = SMC_inw( RXFIFO_REG );
+
+	if ( packet_number & RXFIFO_REMPTY ) {
+
+		return 0;
+	}
+
+	PRINTK3("%s: smc_rcv\n", SMC_DEV_NAME);
+	/*  start reading from the start of the packet */
+	SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG );
+
+	/* First two words are status and packet_length */
+#ifdef USE_32_BIT
+	stat_len = SMC_inl(SMC91111_DATA_REG);
+	status = stat_len & 0xffff;
+	packet_length = stat_len >> 16;
+#else
+	status		= SMC_inw( SMC91111_DATA_REG );
+	packet_length	= SMC_inw( SMC91111_DATA_REG );
+#endif
+
+	packet_length &= 0x07ff;  /* mask off top bits */
+
+	PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );
+
+	if ( !(status & RS_ERRORS ) ){
+		/* Adjust for having already read the first two words */
+		packet_length -= 4; /*4; */
+
+
+		/* set odd length for bug in LAN91C111, */
+		/* which never sets RS_ODDFRAME */
+		/* TODO ? */
+
+
+#ifdef USE_32_BIT
+		PRINTK3(" Reading %d dwords (and %d bytes) \n",
+			packet_length >> 2, packet_length & 3 );
+		/* QUESTION:  Like in the TX routine, do I want
+		   to send the DWORDs or the bytes first, or some
+		   mixture.  A mixture might improve already slow PIO
+		   performance	*/
+		SMC_insl( SMC91111_DATA_REG , NetRxPackets[0], packet_length >> 2 );
+		/* read the left over bytes */
+		if (packet_length & 3) {
+			int i;
+
+			byte *tail = (byte *)(NetRxPackets[0] + (packet_length & ~3));
+			dword leftover = SMC_inl(SMC91111_DATA_REG);
+			for (i=0; i<(packet_length & 3); i++)
+				*tail++ = (byte) (leftover >> (8*i)) & 0xff;
+		}
+#else
+		PRINTK3(" Reading %d words and %d byte(s) \n",
+			(packet_length >> 1 ), packet_length & 1 );
+		SMC_insw(SMC91111_DATA_REG , NetRxPackets[0], packet_length >> 1);
+
+#endif /* USE_32_BIT */
+
+#if	SMC_DEBUG > 2
+		printf("Receiving Packet\n");
+		print_packet( NetRxPackets[0], packet_length );
+#endif
+	} else {
+		/* error ... */
+		/* TODO ? */
+		is_error = 1;
+	}
+
+	while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
+		udelay(1); /* Wait until not busy */
+
+	/*  error or good, tell the card to get rid of this packet */
+	SMC_outw( MC_RELEASE, MMU_CMD_REG );
+
+	while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
+		udelay(1); /* Wait until not busy */
+
+	/* restore saved registers */
+#ifndef CONFIG_XAENIAX
+	SMC_outb( saved_pnr, PN_REG );
+#else
+	/* On Xaeniax board, we can't use SMC_outb here because that way
+	 * the Allocate MMU command will end up written to the command register
+	 * as well, which will lead to a problem.
+	 */
+	SMC_outl( saved_pnr << 16, 0);
+#endif
+	SMC_outw( saved_ptr, PTR_REG );
+
+	if (!is_error) {
+		/* Pass the packet up to the protocol layers. */
+		NetReceive(NetRxPackets[0], packet_length);
+		return packet_length;
+	} else {
+		return 0;
+	}
+
+}
+
+
+/*----------------------------------------------------
+ . smc_close
+ .
+ . this makes the board clean up everything that it can
+ . and not talk to the outside world.	Caused by
+ . an 'ifconfig ethX down'
+ .
+ -----------------------------------------------------*/
+static int smc_close()
+{
+	PRINTK2("%s: smc_close\n", SMC_DEV_NAME);
+
+	/* clear everything */
+	smc_shutdown();
+
+	return 0;
+}
+
+
+#if 0
+/*------------------------------------------------------------
+ . Modify a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static word smc_modify_regbit(int bank, int ioaddr, int reg,
+	unsigned int bit, int val)
+{
+	word regval;
+
+	SMC_SELECT_BANK( bank );
+
+	regval = SMC_inw( reg );
+	if (val)
+		regval |= bit;
+	else
+		regval &= ~bit;
+
+	SMC_outw( regval, 0 );
+	return(regval);
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit)
+{
+	SMC_SELECT_BANK( bank );
+	if ( SMC_inw( reg ) & bit)
+		return(1);
+	else
+		return(0);
+}
+
+
+/*------------------------------------------------------------
+ . Modify a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static void smc_modify_reg(int bank, int ioaddr, int reg, word val)
+{
+	SMC_SELECT_BANK( bank );
+	SMC_outw( val, reg );
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static int smc_get_reg(int bank, int ioaddr, int reg)
+{
+	SMC_SELECT_BANK( bank );
+	return(SMC_inw( reg ));
+}
+
+#endif /* 0 */
+
+/*---PHY CONTROL AND CONFIGURATION----------------------------------------- */
+
+#if (SMC_DEBUG > 2 )
+
+/*------------------------------------------------------------
+ . Debugging function for viewing MII Management serial bitstream
+ .-------------------------------------------------------------*/
+static void smc_dump_mii_stream (byte * bits, int size)
+{
+	int i;
+
+	printf ("BIT#:");
+	for (i = 0; i < size; ++i) {
+		printf ("%d", i % 10);
+	}
+
+	printf ("\nMDOE:");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDOE)
+			printf ("1");
+		else
+			printf ("0");
+	}
+
+	printf ("\nMDO :");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDO)
+			printf ("1");
+		else
+			printf ("0");
+	}
+
+	printf ("\nMDI :");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDI)
+			printf ("1");
+		else
+			printf ("0");
+	}
+
+	printf ("\n");
+}
+#endif
+
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static word smc_read_phy_register (byte phyreg)
+{
+	int oldBank;
+	int i;
+	byte mask;
+	word mii_reg;
+	byte bits[64];
+	int clk_idx = 0;
+	int input_idx;
+	word phydata;
+	byte phyaddr = SMC_PHY_ADDR;
+
+	/* 32 consecutive ones on MDO to establish sync */
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	/* Start code <01> */
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	/* Read command <10> */
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+	bits[clk_idx++] = MII_MDOE;
+
+	/* Output the PHY address, msb first */
+	mask = (byte) 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		/* Shift to next lowest bit */
+		mask >>= 1;
+	}
+
+	/* Output the phy register number, msb first */
+	mask = (byte) 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		/* Shift to next lowest bit */
+		mask >>= 1;
+	}
+
+	/* Tristate and turnaround (2 bit times) */
+	bits[clk_idx++] = 0;
+	/*bits[clk_idx++] = 0; */
+
+	/* Input starts at this bit time */
+	input_idx = clk_idx;
+
+	/* Will input 16 bits */
+	for (i = 0; i < 16; ++i)
+		bits[clk_idx++] = 0;
+
+	/* Final clock bit */
+	bits[clk_idx++] = 0;
+
+	/* Save the current bank */
+	oldBank = SMC_inw (BANK_SELECT);
+
+	/* Select bank 3 */
+	SMC_SELECT_BANK (3);
+
+	/* Get the current MII register value */
+	mii_reg = SMC_inw (MII_REG);
+
+	/* Turn off all MII Interface bits */
+	mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);
+
+	/* Clock all 64 cycles */
+	for (i = 0; i < sizeof bits; ++i) {
+		/* Clock Low - output data */
+		SMC_outw (mii_reg | bits[i], MII_REG);
+		udelay (SMC_PHY_CLOCK_DELAY);
+
+
+		/* Clock Hi - input data */
+		SMC_outw (mii_reg | bits[i] | MII_MCLK, MII_REG);
+		udelay (SMC_PHY_CLOCK_DELAY);
+		bits[i] |= SMC_inw (MII_REG) & MII_MDI;
+	}
+
+	/* Return to idle state */
+	/* Set clock to low, data to low, and output tristated */
+	SMC_outw (mii_reg, MII_REG);
+	udelay (SMC_PHY_CLOCK_DELAY);
+
+	/* Restore original bank select */
+	SMC_SELECT_BANK (oldBank);
+
+	/* Recover input data */
+	phydata = 0;
+	for (i = 0; i < 16; ++i) {
+		phydata <<= 1;
+
+		if (bits[input_idx++] & MII_MDI)
+			phydata |= 0x0001;
+	}
+
+#if (SMC_DEBUG > 2 )
+	printf ("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+		phyaddr, phyreg, phydata);
+	smc_dump_mii_stream (bits, sizeof bits);
+#endif
+
+	return (phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register (byte phyreg, word phydata)
+{
+	int oldBank;
+	int i;
+	word mask;
+	word mii_reg;
+	byte bits[65];
+	int clk_idx = 0;
+	byte phyaddr = SMC_PHY_ADDR;
+
+	/* 32 consecutive ones on MDO to establish sync */
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	/* Start code <01> */
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	/* Write command <01> */
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	/* Output the PHY address, msb first */
+	mask = (byte) 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		/* Shift to next lowest bit */
+		mask >>= 1;
+	}
+
+	/* Output the phy register number, msb first */
+	mask = (byte) 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		/* Shift to next lowest bit */
+		mask >>= 1;
+	}
+
+	/* Tristate and turnaround (2 bit times) */
+	bits[clk_idx++] = 0;
+	bits[clk_idx++] = 0;
+
+	/* Write out 16 bits of data, msb first */
+	mask = 0x8000;
+	for (i = 0; i < 16; ++i) {
+		if (phydata & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		/* Shift to next lowest bit */
+		mask >>= 1;
+	}
+
+	/* Final clock bit (tristate) */
+	bits[clk_idx++] = 0;
+
+	/* Save the current bank */
+	oldBank = SMC_inw (BANK_SELECT);
+
+	/* Select bank 3 */
+	SMC_SELECT_BANK (3);
+
+	/* Get the current MII register value */
+	mii_reg = SMC_inw (MII_REG);
+
+	/* Turn off all MII Interface bits */
+	mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);
+
+	/* Clock all cycles */
+	for (i = 0; i < sizeof bits; ++i) {
+		/* Clock Low - output data */
+		SMC_outw (mii_reg | bits[i], MII_REG);
+		udelay (SMC_PHY_CLOCK_DELAY);
+
+
+		/* Clock Hi - input data */
+		SMC_outw (mii_reg | bits[i] | MII_MCLK, MII_REG);
+		udelay (SMC_PHY_CLOCK_DELAY);
+		bits[i] |= SMC_inw (MII_REG) & MII_MDI;
+	}
+
+	/* Return to idle state */
+	/* Set clock to low, data to low, and output tristated */
+	SMC_outw (mii_reg, MII_REG);
+	udelay (SMC_PHY_CLOCK_DELAY);
+
+	/* Restore original bank select */
+	SMC_SELECT_BANK (oldBank);
+
+#if (SMC_DEBUG > 2 )
+	printf ("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+		phyaddr, phyreg, phydata);
+	smc_dump_mii_stream (bits, sizeof bits);
+#endif
+}
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+/*------------------------------------------------------------
+ . Waits the specified number of milliseconds - kernel friendly
+ .-------------------------------------------------------------*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static void smc_wait_ms(unsigned int ms)
+{
+	udelay(ms*1000);
+}
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static void smc_phy_configure ()
+{
+	int timeout;
+	byte phyaddr;
+	word my_phy_caps;	/* My PHY capabilities */
+	word my_ad_caps;	/* My Advertised capabilities */
+	word status = 0;	/*;my status = 0 */
+	int failed = 0;
+
+	PRINTK3 ("%s: smc_program_phy()\n", SMC_DEV_NAME);
+
+
+	/* Get the detected phy address */
+	phyaddr = SMC_PHY_ADDR;
+
+	/* Reset the PHY, setting all other bits to zero */
+	smc_write_phy_register (PHY_CNTL_REG, PHY_CNTL_RST);
+
+	/* Wait for the reset to complete, or time out */
+	timeout = 6;		/* Wait up to 3 seconds */
+	while (timeout--) {
+		if (!(smc_read_phy_register (PHY_CNTL_REG)
+		      & PHY_CNTL_RST)) {
+			/* reset complete */
+			break;
+		}
+
+		smc_wait_ms (500);	/* wait 500 millisecs */
+	}
+
+	if (timeout < 1) {
+		printf ("%s:PHY reset timed out\n", SMC_DEV_NAME);
+		goto smc_phy_configure_exit;
+	}
+
+	/* Read PHY Register 18, Status Output */
+	/* lp->lastPhy18 = smc_read_phy_register(PHY_INT_REG); */
+
+	/* Enable PHY Interrupts (for register 18) */
+	/* Interrupts listed here are disabled */
+	smc_write_phy_register (PHY_MASK_REG, 0xffff);
+
+	/* Configure the Receive/Phy Control register */
+	SMC_SELECT_BANK (0);
+	SMC_outw (RPC_DEFAULT, RPC_REG);
+
+	/* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
+	my_phy_caps = smc_read_phy_register (PHY_STAT_REG);
+	my_ad_caps = PHY_AD_CSMA;	/* I am CSMA capable */
+
+	if (my_phy_caps & PHY_STAT_CAP_T4)
+		my_ad_caps |= PHY_AD_T4;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXF)
+		my_ad_caps |= PHY_AD_TX_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXH)
+		my_ad_caps |= PHY_AD_TX_HDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TF)
+		my_ad_caps |= PHY_AD_10_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TH)
+		my_ad_caps |= PHY_AD_10_HDX;
+
+	/* Update our Auto-Neg Advertisement Register */
+	smc_write_phy_register (PHY_AD_REG, my_ad_caps);
+
+	/* Read the register back.  Without this, it appears that when */
+	/* auto-negotiation is restarted, sometimes it isn't ready and */
+	/* the link does not come up. */
+	smc_read_phy_register(PHY_AD_REG);
+
+	PRINTK2 ("%s: phy caps=%x\n", SMC_DEV_NAME, my_phy_caps);
+	PRINTK2 ("%s: phy advertised caps=%x\n", SMC_DEV_NAME, my_ad_caps);
+
+	/* Restart auto-negotiation process in order to advertise my caps */
+	smc_write_phy_register (PHY_CNTL_REG,
+				PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
+
+	/* Wait for the auto-negotiation to complete.  This may take from */
+	/* 2 to 3 seconds. */
+	/* Wait for the reset to complete, or time out */
+	timeout = CONFIG_SMC_AUTONEG_TIMEOUT * 2;
+	while (timeout--) {
+
+		status = smc_read_phy_register (PHY_STAT_REG);
+		if (status & PHY_STAT_ANEG_ACK) {
+			/* auto-negotiate complete */
+			break;
+		}
+
+		smc_wait_ms (500);	/* wait 500 millisecs */
+
+		/* Restart auto-negotiation if remote fault */
+		if (status & PHY_STAT_REM_FLT) {
+			printf ("%s: PHY remote fault detected\n",
+				SMC_DEV_NAME);
+
+			/* Restart auto-negotiation */
+			printf ("%s: PHY restarting auto-negotiation\n",
+				SMC_DEV_NAME);
+			smc_write_phy_register (PHY_CNTL_REG,
+						PHY_CNTL_ANEG_EN |
+						PHY_CNTL_ANEG_RST |
+						PHY_CNTL_SPEED |
+						PHY_CNTL_DPLX);
+		}
+	}
+
+	if (timeout < 1) {
+		printf ("%s: PHY auto-negotiate timed out\n", SMC_DEV_NAME);
+		failed = 1;
+	}
+
+	/* Fail if we detected an auto-negotiate remote fault */
+	if (status & PHY_STAT_REM_FLT) {
+		printf ("%s: PHY remote fault detected\n", SMC_DEV_NAME);
+		failed = 1;
+	}
+
+	/* Re-Configure the Receive/Phy Control register */
+	SMC_outw (RPC_DEFAULT, RPC_REG);
+
+smc_phy_configure_exit:	;
+
+}
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+#if SMC_DEBUG > 2
+static void print_packet( byte * buf, int length )
+{
+	int i;
+	int remainder;
+	int lines;
+
+	printf("Packet of length %d \n", length );
+
+#if SMC_DEBUG > 3
+	lines = length / 16;
+	remainder = length % 16;
+
+	for ( i = 0; i < lines ; i ++ ) {
+		int cur;
+
+		for ( cur = 0; cur < 8; cur ++ ) {
+			byte a, b;
+
+			a = *(buf ++ );
+			b = *(buf ++ );
+			printf("%02x%02x ", a, b );
+		}
+		printf("\n");
+	}
+	for ( i = 0; i < remainder/2 ; i++ ) {
+		byte a, b;
+
+		a = *(buf ++ );
+		b = *(buf ++ );
+		printf("%02x%02x ", a, b );
+	}
+	printf("\n");
+#endif
+}
+#endif
+
+int eth_init(bd_t *bd) {
+#ifdef SHARED_RESOURCES
+	swap_to(ETHERNET);
+#endif
+	return (smc_open(bd));
+}
+
+void eth_halt() {
+	smc_close();
+}
+
+int eth_rx() {
+	return smc_rcv();
+}
+
+int eth_send(volatile void *packet, int length) {
+	return smc_send_packet(packet, length);
+}
+
+int smc_get_ethaddr (bd_t * bd)
+{
+	int env_size, rom_valid, env_present = 0, reg;
+	char *s = NULL, *e, es[] = "11:22:33:44:55:66";
+	char s_env_mac[64];
+	uchar v_env_mac[6], v_rom_mac[6], *v_mac;
+
+	env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
+	if ((env_size > 0) && (env_size < sizeof (es))) {	/* exit if env is bad */
+		printf ("\n*** ERROR: ethaddr is not set properly!!\n");
+		return (-1);
+	}
+
+	if (env_size > 0) {
+		env_present = 1;
+		s = s_env_mac;
+	}
+
+	for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
+		v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
+		if (s)
+			s = (*e) ? e + 1 : e;
+	}
+
+	rom_valid = get_rom_mac (v_rom_mac);	/* get ROM mac value if any */
+
+	if (!env_present) {	/* if NO env */
+		if (rom_valid) {	/* but ROM is valid */
+			v_mac = v_rom_mac;
+			sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
+				 v_mac[0], v_mac[1], v_mac[2], v_mac[3],
+				 v_mac[4], v_mac[5]);
+			setenv ("ethaddr", s_env_mac);
+		} else {	/* no env, bad ROM */
+			printf ("\n*** ERROR: ethaddr is NOT set !!\n");
+			return (-1);
+		}
+	} else {		/* good env, don't care ROM */
+		v_mac = v_env_mac;	/* always use a good env over a ROM */
+	}
+
+	if (env_present && rom_valid) { /* if both env and ROM are good */
+		if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
+			printf ("\nWarning: MAC addresses don't match:\n");
+			printf ("\tHW MAC address:  "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				v_rom_mac[0], v_rom_mac[1],
+				v_rom_mac[2], v_rom_mac[3],
+				v_rom_mac[4], v_rom_mac[5] );
+			printf ("\t\"ethaddr\" value: "
+				"%02X:%02X:%02X:%02X:%02X:%02X\n",
+				v_env_mac[0], v_env_mac[1],
+				v_env_mac[2], v_env_mac[3],
+				v_env_mac[4], v_env_mac[5]) ;
+			debug ("### Set MAC addr from environment\n");
+		}
+	}
+	memcpy (bd->bi_enetaddr, v_mac, 6);	/* update global address to match env (allows env changing) */
+	smc_set_mac_addr ((uchar *)v_mac);	/* use old function to update smc default */
+	PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
+		v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
+	return (0);
+}
+
+int get_rom_mac (uchar *v_rom_mac)
+{
+#ifdef HARDCODE_MAC	/* used for testing or to supress run time warnings */
+	char hw_mac_addr[] = { 0x02, 0x80, 0xad, 0x20, 0x31, 0xb8 };
+
+	memcpy (v_rom_mac, hw_mac_addr, 6);
+	return (1);
+#else
+	int i;
+	int valid_mac = 0;
+
+	SMC_SELECT_BANK (1);
+	for (i=0; i<6; i++)
+	{
+		v_rom_mac[i] = SMC_inb ((ADDR0_REG + i));
+		valid_mac |= v_rom_mac[i];
+	}
+
+	return (valid_mac ? 1 : 0);
+#endif
+}
+#endif /* CONFIG_DRIVER_SMC91111 */
diff --git a/drivers/net/smc91111.h b/drivers/net/smc91111.h
new file mode 100644
index 0000000..d03cbc3
--- /dev/null
+++ b/drivers/net/smc91111.h
@@ -0,0 +1,719 @@
+/*------------------------------------------------------------------------
+ . smc91111.h - macros for the LAN91C111 Ethernet Driver
+ .
+ . (C) Copyright 2002
+ . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ . Rolf Offermanns <rof@sysgo.de>
+ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ .       Developed by Simple Network Magic Corporation (SNMC)
+ . Copyright (C) 1996 by Erik Stahlman (ES)
+ .
+ . 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.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . This file contains register information and access macros for
+ . the LAN91C111 single chip ethernet controller.  It is a modified
+ . version of the smc9194.h file.
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ . 	Erik Stahlman				( erik@vt.edu )
+ .	Daris A Nevil				( dnevil@snmc.com )
+ .
+ . History
+ . 03/16/01		Daris A Nevil	Modified for use with LAN91C111 device
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC91111_H_
+#define _SMC91111_H_
+
+#include <asm/types.h>
+#include <config.h>
+
+/*
+ * This function may be called by the board specific initialisation code
+ * in order to override the default mac address.
+ */
+
+void smc_set_mac_addr (const unsigned char *addr);
+
+
+/* I want some simple types */
+
+typedef unsigned char			byte;
+typedef unsigned short			word;
+typedef unsigned long int 		dword;
+
+/*
+ . DEBUGGING LEVELS
+ .
+ . 0 for normal operation
+ . 1 for slightly more details
+ . >2 for various levels of increasingly useless information
+ .    2 for interrupt tracking, status flags
+ .    3 for packet info
+ .    4 for complete packet dumps
+*/
+/*#define SMC_DEBUG 0 */
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define	SMC_IO_EXTENT	16
+
+#ifdef CONFIG_PXA250
+
+#ifdef CONFIG_XSENGINE
+#define	SMC_inl(r) 	(*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1))))
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+(r<<1))))
+#define SMC_inb(p)	({ \
+	unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (p<<1)); \
+	unsigned int __v = *(volatile unsigned short *)((__p) & ~2); \
+	if (__p & 2) __v >>= 8; \
+	else __v &= 0xff; \
+	__v; })
+#elif defined(CONFIG_XAENIAX)
+#define SMC_inl(r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))))
+#define SMC_inw(z)	({ \
+	unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (z)); \
+	unsigned int __v = *(volatile unsigned int *)((__p) & ~3); \
+	if (__p & 3) __v >>= 16; \
+	else __v &= 0xffff; \
+	__v; })
+#define SMC_inb(p)	({ \
+	unsigned int ___v = SMC_inw((p) & ~1); \
+	if (p & 1) ___v >>= 8; \
+	else ___v &= 0xff; \
+	___v; })
+#else
+#define	SMC_inl(r) 	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))))
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+(r))))
+#define SMC_inb(p)	({ \
+	unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (p)); \
+	unsigned int __v = *(volatile unsigned short *)((__p) & ~1); \
+	if (__p & 1) __v >>= 8; \
+	else __v &= 0xff; \
+	__v; })
+#endif
+
+#ifdef CONFIG_XSENGINE
+#define	SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1))) = d)
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r<<1))) = d)
+#elif defined (CONFIG_XAENIAX)
+#define SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))) = d)
+#define SMC_outw(d,p)	({ \
+	dword __dwo = SMC_inl((p) & ~3); \
+	dword __dwn = (word)(d); \
+	__dwo &= ((p) & 3) ? 0x0000ffff : 0xffff0000; \
+	__dwo |= ((p) & 3) ? __dwn << 16 : __dwn; \
+	SMC_outl(__dwo, (p) & ~3); \
+})
+#else
+#define	SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))) = d)
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d)
+#endif
+
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+
+#define SMC_outsl(r,b,l)	({	int __i; \
+					dword *__b2; \
+					__b2 = (dword *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outl( *(__b2 + __i), r); \
+					} \
+				})
+
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r); \
+					} \
+				})
+
+#define SMC_insl(r,b,l) 	({	int __i ;  \
+					dword *__b2;  \
+			    		__b2 = (dword *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inl(r);  \
+					  SMC_inl(0);  \
+					};  \
+				})
+
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+			    		__b2 = (word *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+
+#define SMC_insb(r,b,l) 	({	int __i ;  \
+					byte *__b2;  \
+			    		__b2 = (byte *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inb(r);  \
+					  SMC_inb(0);  \
+					};  \
+				})
+
+#else /* if not CONFIG_PXA250 */
+
+#ifndef CONFIG_SMC_USE_IOFUNCS /* these macros don't work on some boards */
+/*
+ * We have only 16 Bit PCMCIA access on Socket 0
+ */
+
+#ifdef CONFIG_ADNPESC1
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+((r)<<1))))
+#elif CONFIG_BLACKFIN
+#define	SMC_inw(r) 	({ word __v = (*((volatile word *)(SMC_BASE_ADDRESS+(r)))); asm("ssync;"); __v;})
+#else
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+(r))))
+#endif
+#define  SMC_inb(r)	(((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF)
+
+#ifdef CONFIG_ADNPESC1
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+((r)<<1))) = d)
+#elif CONFIG_BLACKFIN
+#define	SMC_outw(d,r)	{(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d);asm("ssync;");}
+#else
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d)
+#endif
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+#if 0
+#define	SMC_outsw(r,b,l)	outsw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r); \
+					} \
+				})
+#endif
+
+#if 0
+#define	SMC_insw(r,b,l) 	insw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+			    		__b2 = (word *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+#endif
+
+#endif  /* CONFIG_SMC_USE_IOFUNCS */
+
+#if defined(CONFIG_SMC_USE_32_BIT)
+
+#ifdef CONFIG_XSENGINE
+#define	SMC_inl(r) 	(*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1))))
+#else
+#define	SMC_inl(r) 	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))))
+#endif
+
+#define SMC_insl(r,b,l) 	({	int __i ;  \
+					dword *__b2;  \
+			    		__b2 = (dword *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inl(r);  \
+					  SMC_inl(0);  \
+					};  \
+				})
+
+#ifdef CONFIG_XSENGINE
+#define	SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1))) = d)
+#else
+#define	SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r))) = d)
+#endif
+#define SMC_outsl(r,b,l)	({	int __i; \
+					dword *__b2; \
+					__b2 = (dword *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outl( *(__b2 + __i), r); \
+					} \
+				})
+
+#endif /* CONFIG_SMC_USE_32_BIT */
+
+#endif
+
+/*---------------------------------------------------------------
+ .
+ . A description of the SMSC registers is probably in order here,
+ . although for details, the SMC datasheet is invaluable.
+ .
+ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ . are accessed by writing a number into the BANK_SELECT register
+ . ( I also use a SMC_SELECT_BANK macro for this ).
+ .
+ . The banks are configured so that for most purposes, bank 2 is all
+ . that is needed for simple run time tasks.
+ -----------------------------------------------------------------------*/
+
+/*
+ . Bank Select Register:
+ .
+ .		yyyy yyyy 0000 00xx
+ .		xx 		= bank number
+ .		yyyy yyyy	= 0x33, for identification purposes.
+*/
+#define	BANK_SELECT		14
+
+/* Transmit Control Register */
+/* BANK 0  */
+#define	TCR_REG 	0x0000 	/* transmit control register */
+#define TCR_ENABLE	0x0001	/* When 1 we can transmit */
+#define TCR_LOOP	0x0002	/* Controls output pin LBK */
+#define TCR_FORCOL	0x0004	/* When 1 will force a collision */
+#define TCR_PAD_EN	0x0080	/* When 1 will pad tx frames < 64 bytes w/0 */
+#define TCR_NOCRC	0x0100	/* When 1 will not append CRC to tx frames */
+#define TCR_MON_CSN	0x0400	/* When 1 tx monitors carrier */
+#define TCR_FDUPLX    	0x0800  /* When 1 enables full duplex operation */
+#define TCR_STP_SQET	0x1000	/* When 1 stops tx if Signal Quality Error */
+#define	TCR_EPH_LOOP	0x2000	/* When 1 enables EPH block loopback */
+#define	TCR_SWFDUP	0x8000	/* When 1 enables Switched Full Duplex mode */
+
+#define	TCR_CLEAR	0	/* do NOTHING */
+/* the default settings for the TCR register : */
+/* QUESTION: do I want to enable padding of short packets ? */
+#define	TCR_DEFAULT  	TCR_ENABLE
+
+
+/* EPH Status Register */
+/* BANK 0  */
+#define EPH_STATUS_REG	0x0002
+#define ES_TX_SUC	0x0001	/* Last TX was successful */
+#define ES_SNGL_COL	0x0002	/* Single collision detected for last tx */
+#define ES_MUL_COL	0x0004	/* Multiple collisions detected for last tx */
+#define ES_LTX_MULT	0x0008	/* Last tx was a multicast */
+#define ES_16COL	0x0010	/* 16 Collisions Reached */
+#define ES_SQET		0x0020	/* Signal Quality Error Test */
+#define ES_LTXBRD	0x0040	/* Last tx was a broadcast */
+#define ES_TXDEFR	0x0080	/* Transmit Deferred */
+#define ES_LATCOL	0x0200	/* Late collision detected on last tx */
+#define ES_LOSTCARR	0x0400	/* Lost Carrier Sense */
+#define ES_EXC_DEF	0x0800	/* Excessive Deferral */
+#define ES_CTR_ROL	0x1000	/* Counter Roll Over indication */
+#define ES_LINK_OK	0x4000	/* Driven by inverted value of nLNK pin */
+#define ES_TXUNRN	0x8000	/* Tx Underrun */
+
+
+/* Receive Control Register */
+/* BANK 0  */
+#define	RCR_REG		0x0004
+#define	RCR_RX_ABORT	0x0001	/* Set if a rx frame was aborted */
+#define	RCR_PRMS	0x0002	/* Enable promiscuous mode */
+#define	RCR_ALMUL	0x0004	/* When set accepts all multicast frames */
+#define RCR_RXEN	0x0100	/* IFF this is set, we can receive packets */
+#define	RCR_STRIP_CRC	0x0200	/* When set strips CRC from rx packets */
+#define	RCR_ABORT_ENB	0x0200	/* When set will abort rx on collision */
+#define	RCR_FILT_CAR	0x0400	/* When set filters leading 12 bit s of carrier */
+#define RCR_SOFTRST	0x8000 	/* resets the chip */
+
+/* the normal settings for the RCR register : */
+#define	RCR_DEFAULT	(RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR	0x0	/* set it to a base state */
+
+/* Counter Register */
+/* BANK 0  */
+#define	COUNTER_REG	0x0006
+
+/* Memory Information Register */
+/* BANK 0  */
+#define	MIR_REG		0x0008
+
+/* Receive/Phy Control Register */
+/* BANK 0  */
+#define	RPC_REG		0x000A
+#define	RPC_SPEED	0x2000	/* When 1 PHY is in 100Mbps mode. */
+#define	RPC_DPLX	0x1000	/* When 1 PHY is in Full-Duplex Mode */
+#define	RPC_ANEG	0x0800	/* When 1 PHY is in Auto-Negotiate Mode */
+#define	RPC_LSXA_SHFT	5	/* Bits to shift LS2A,LS1A,LS0A to lsb */
+#define	RPC_LSXB_SHFT	2	/* Bits to get LS2B,LS1B,LS0B to lsb */
+#define RPC_LED_100_10	(0x00)	/* LED = 100Mbps OR's with 10Mbps link detect */
+#define RPC_LED_RES	(0x01)	/* LED = Reserved */
+#define RPC_LED_10	(0x02)	/* LED = 10Mbps link detect */
+#define RPC_LED_FD	(0x03)	/* LED = Full Duplex Mode */
+#define RPC_LED_TX_RX	(0x04)	/* LED = TX or RX packet occurred */
+#define RPC_LED_100	(0x05)	/* LED = 100Mbps link dectect */
+#define RPC_LED_TX	(0x06)	/* LED = TX packet occurred */
+#define RPC_LED_RX	(0x07)	/* LED = RX packet occurred */
+#if defined(CONFIG_DK1C20) || defined(CONFIG_DK1S10)
+/* buggy schematic: LEDa -> yellow, LEDb --> green */
+#define RPC_DEFAULT	( RPC_SPEED | RPC_DPLX | RPC_ANEG	\
+			| (RPC_LED_TX_RX << RPC_LSXA_SHFT)	\
+			| (RPC_LED_100_10 << RPC_LSXB_SHFT)	)
+#elif defined(CONFIG_ADNPESC1)
+/* SSV ADNP/ESC1 has only one LED: LEDa -> Rx/Tx indicator */
+#define RPC_DEFAULT	( RPC_SPEED | RPC_DPLX | RPC_ANEG	\
+			| (RPC_LED_TX_RX << RPC_LSXA_SHFT)	\
+			| (RPC_LED_100_10 << RPC_LSXB_SHFT)	)
+#else
+/* SMSC reference design: LEDa --> green, LEDb --> yellow */
+#define RPC_DEFAULT	( RPC_SPEED | RPC_DPLX | RPC_ANEG	\
+			| (RPC_LED_100_10 << RPC_LSXA_SHFT)	\
+			| (RPC_LED_TX_RX << RPC_LSXB_SHFT)	)
+#endif
+
+/* Bank 0 0x000C is reserved */
+
+/* Bank Select Register */
+/* All Banks */
+#define BSR_REG	0x000E
+
+
+/* Configuration Reg */
+/* BANK 1 */
+#define CONFIG_REG	0x0000
+#define CONFIG_EXT_PHY	0x0200	/* 1=external MII, 0=internal Phy */
+#define CONFIG_GPCNTRL	0x0400	/* Inverse value drives pin nCNTRL */
+#define CONFIG_NO_WAIT	0x1000	/* When 1 no extra wait states on ISA bus */
+#define CONFIG_EPH_POWER_EN 0x8000 /* When 0 EPH is placed into low power mode. */
+
+/* Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low */
+#define CONFIG_DEFAULT	(CONFIG_EPH_POWER_EN)
+
+
+/* Base Address Register */
+/* BANK 1 */
+#define	BASE_REG	0x0002
+
+
+/* Individual Address Registers */
+/* BANK 1 */
+#define	ADDR0_REG	0x0004
+#define	ADDR1_REG	0x0006
+#define	ADDR2_REG	0x0008
+
+
+/* General Purpose Register */
+/* BANK 1 */
+#define	GP_REG		0x000A
+
+
+/* Control Register */
+/* BANK 1 */
+#define	CTL_REG		0x000C
+#define CTL_RCV_BAD	0x4000 /* When 1 bad CRC packets are received */
+#define CTL_AUTO_RELEASE 0x0800 /* When 1 tx pages are released automatically */
+#define	CTL_LE_ENABLE	0x0080 /* When 1 enables Link Error interrupt */
+#define	CTL_CR_ENABLE	0x0040 /* When 1 enables Counter Rollover interrupt */
+#define	CTL_TE_ENABLE	0x0020 /* When 1 enables Transmit Error interrupt */
+#define	CTL_EEPROM_SELECT 0x0004 /* Controls EEPROM reload & store */
+#define	CTL_RELOAD	0x0002 /* When set reads EEPROM into registers */
+#define	CTL_STORE	0x0001 /* When set stores registers into EEPROM */
+#define CTL_DEFAULT     (0x1A10) /* Autorelease enabled*/
+
+/* MMU Command Register */
+/* BANK 2 */
+#define MMU_CMD_REG	0x0000
+#define MC_BUSY		1	/* When 1 the last release has not completed */
+#define MC_NOP		(0<<5)	/* No Op */
+#define	MC_ALLOC	(1<<5) 	/* OR with number of 256 byte packets */
+#define	MC_RESET	(2<<5)	/* Reset MMU to initial state */
+#define	MC_REMOVE	(3<<5) 	/* Remove the current rx packet */
+#define MC_RELEASE  	(4<<5) 	/* Remove and release the current rx packet */
+#define MC_FREEPKT  	(5<<5) 	/* Release packet in PNR register */
+#define MC_ENQUEUE	(6<<5)	/* Enqueue the packet for transmit */
+#define MC_RSTTXFIFO	(7<<5)	/* Reset the TX FIFOs */
+
+
+/* Packet Number Register */
+/* BANK 2 */
+#define	PN_REG		0x0002
+
+
+/* Allocation Result Register */
+/* BANK 2 */
+#define	AR_REG		0x0003
+#define AR_FAILED	0x80	/* Alocation Failed */
+
+
+/* RX FIFO Ports Register */
+/* BANK 2 */
+#define RXFIFO_REG	0x0004	/* Must be read as a word */
+#define RXFIFO_REMPTY	0x8000	/* RX FIFO Empty */
+
+
+/* TX FIFO Ports Register */
+/* BANK 2 */
+#define TXFIFO_REG	RXFIFO_REG	/* Must be read as a word */
+#define TXFIFO_TEMPTY	0x80	/* TX FIFO Empty */
+
+
+/* Pointer Register */
+/* BANK 2 */
+#define PTR_REG		0x0006
+#define	PTR_RCV		0x8000 /* 1=Receive area, 0=Transmit area */
+#define	PTR_AUTOINC 	0x4000 /* Auto increment the pointer on each access */
+#define PTR_READ	0x2000 /* When 1 the operation is a read */
+#define PTR_NOTEMPTY	0x0800 /* When 1 _do not_ write fifo DATA REG */
+
+
+/* Data Register */
+/* BANK 2 */
+#define	SMC91111_DATA_REG	0x0008
+
+
+/* Interrupt Status/Acknowledge Register */
+/* BANK 2 */
+#define	SMC91111_INT_REG	0x000C
+
+
+/* Interrupt Mask Register */
+/* BANK 2 */
+#define IM_REG		0x000D
+#define	IM_MDINT	0x80 /* PHY MI Register 18 Interrupt */
+#define	IM_ERCV_INT	0x40 /* Early Receive Interrupt */
+#define	IM_EPH_INT	0x20 /* Set by Etheret Protocol Handler section */
+#define	IM_RX_OVRN_INT	0x10 /* Set by Receiver Overruns */
+#define	IM_ALLOC_INT	0x08 /* Set when allocation request is completed */
+#define	IM_TX_EMPTY_INT	0x04 /* Set if the TX FIFO goes empty */
+#define	IM_TX_INT	0x02 /* Transmit Interrrupt */
+#define IM_RCV_INT	0x01 /* Receive Interrupt */
+
+
+/* Multicast Table Registers */
+/* BANK 3 */
+#define	MCAST_REG1	0x0000
+#define	MCAST_REG2	0x0002
+#define	MCAST_REG3	0x0004
+#define	MCAST_REG4	0x0006
+
+
+/* Management Interface Register (MII) */
+/* BANK 3 */
+#define	MII_REG		0x0008
+#define MII_MSK_CRS100	0x4000 /* Disables CRS100 detection during tx half dup */
+#define MII_MDOE	0x0008 /* MII Output Enable */
+#define MII_MCLK	0x0004 /* MII Clock, pin MDCLK */
+#define MII_MDI		0x0002 /* MII Input, pin MDI */
+#define MII_MDO		0x0001 /* MII Output, pin MDO */
+
+
+/* Revision Register */
+/* BANK 3 */
+#define	REV_REG		0x000A /* ( hi: chip id   low: rev # ) */
+
+
+/* Early RCV Register */
+/* BANK 3 */
+/* this is NOT on SMC9192 */
+#define	ERCV_REG	0x000C
+#define ERCV_RCV_DISCRD	0x0080 /* When 1 discards a packet being received */
+#define ERCV_THRESHOLD	0x001F /* ERCV Threshold Mask */
+
+/* External Register */
+/* BANK 7 */
+#define	EXT_REG		0x0000
+
+
+#define CHIP_9192	3
+#define CHIP_9194	4
+#define CHIP_9195	5
+#define CHIP_9196	6
+#define CHIP_91100	7
+#define CHIP_91100FD	8
+#define CHIP_91111FD	9
+
+#if 0
+static const char * chip_ids[ 15 ] =  {
+	NULL, NULL, NULL,
+	/* 3 */ "SMC91C90/91C92",
+	/* 4 */ "SMC91C94",
+	/* 5 */ "SMC91C95",
+	/* 6 */ "SMC91C96",
+	/* 7 */ "SMC91C100",
+	/* 8 */ "SMC91C100FD",
+	/* 9 */ "SMC91C111",
+	NULL, NULL,
+	NULL, NULL, NULL};
+#endif
+
+/*
+ . Transmit status bits
+*/
+#define TS_SUCCESS 0x0001
+#define TS_LOSTCAR 0x0400
+#define TS_LATCOL  0x0200
+#define TS_16COL   0x0010
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR	0x8000
+#define RS_BRODCAST	0x4000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000	/* bug: the LAN91C111 never sets this on receive */
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+
+/* PHY Types */
+enum {
+	PHY_LAN83C183 = 1,	/* LAN91C111 Internal PHY */
+	PHY_LAN83C180
+};
+
+
+/* PHY Register Addresses (LAN91C111 Internal PHY) */
+
+/* PHY Control Register */
+#define PHY_CNTL_REG		0x00
+#define PHY_CNTL_RST		0x8000	/* 1=PHY Reset */
+#define PHY_CNTL_LPBK		0x4000	/* 1=PHY Loopback */
+#define PHY_CNTL_SPEED		0x2000	/* 1=100Mbps, 0=10Mpbs */
+#define PHY_CNTL_ANEG_EN	0x1000 /* 1=Enable Auto negotiation */
+#define PHY_CNTL_PDN		0x0800	/* 1=PHY Power Down mode */
+#define PHY_CNTL_MII_DIS	0x0400	/* 1=MII 4 bit interface disabled */
+#define PHY_CNTL_ANEG_RST	0x0200 /* 1=Reset Auto negotiate */
+#define PHY_CNTL_DPLX		0x0100	/* 1=Full Duplex, 0=Half Duplex */
+#define PHY_CNTL_COLTST		0x0080	/* 1= MII Colision Test */
+
+/* PHY Status Register */
+#define PHY_STAT_REG		0x01
+#define PHY_STAT_CAP_T4		0x8000	/* 1=100Base-T4 capable */
+#define PHY_STAT_CAP_TXF	0x4000	/* 1=100Base-X full duplex capable */
+#define PHY_STAT_CAP_TXH	0x2000	/* 1=100Base-X half duplex capable */
+#define PHY_STAT_CAP_TF		0x1000	/* 1=10Mbps full duplex capable */
+#define PHY_STAT_CAP_TH		0x0800	/* 1=10Mbps half duplex capable */
+#define PHY_STAT_CAP_SUPR	0x0040	/* 1=recv mgmt frames with not preamble */
+#define PHY_STAT_ANEG_ACK	0x0020	/* 1=ANEG has completed */
+#define PHY_STAT_REM_FLT	0x0010	/* 1=Remote Fault detected */
+#define PHY_STAT_CAP_ANEG	0x0008	/* 1=Auto negotiate capable */
+#define PHY_STAT_LINK		0x0004	/* 1=valid link */
+#define PHY_STAT_JAB		0x0002	/* 1=10Mbps jabber condition */
+#define PHY_STAT_EXREG		0x0001	/* 1=extended registers implemented */
+
+/* PHY Identifier Registers */
+#define PHY_ID1_REG		0x02	/* PHY Identifier 1 */
+#define PHY_ID2_REG		0x03	/* PHY Identifier 2 */
+
+/* PHY Auto-Negotiation Advertisement Register */
+#define PHY_AD_REG		0x04
+#define PHY_AD_NP		0x8000	/* 1=PHY requests exchange of Next Page */
+#define PHY_AD_ACK		0x4000	/* 1=got link code word from remote */
+#define PHY_AD_RF		0x2000	/* 1=advertise remote fault */
+#define PHY_AD_T4		0x0200	/* 1=PHY is capable of 100Base-T4 */
+#define PHY_AD_TX_FDX		0x0100	/* 1=PHY is capable of 100Base-TX FDPLX */
+#define PHY_AD_TX_HDX		0x0080	/* 1=PHY is capable of 100Base-TX HDPLX */
+#define PHY_AD_10_FDX		0x0040	/* 1=PHY is capable of 10Base-T FDPLX */
+#define PHY_AD_10_HDX		0x0020	/* 1=PHY is capable of 10Base-T HDPLX */
+#define PHY_AD_CSMA		0x0001	/* 1=PHY is capable of 802.3 CMSA */
+
+/* PHY Auto-negotiation Remote End Capability Register */
+#define PHY_RMT_REG		0x05
+/* Uses same bit definitions as PHY_AD_REG */
+
+/* PHY Configuration Register 1 */
+#define PHY_CFG1_REG		0x10
+#define PHY_CFG1_LNKDIS		0x8000	/* 1=Rx Link Detect Function disabled */
+#define PHY_CFG1_XMTDIS		0x4000	/* 1=TP Transmitter Disabled */
+#define PHY_CFG1_XMTPDN		0x2000	/* 1=TP Transmitter Powered Down */
+#define PHY_CFG1_BYPSCR		0x0400	/* 1=Bypass scrambler/descrambler */
+#define PHY_CFG1_UNSCDS		0x0200	/* 1=Unscramble Idle Reception Disable */
+#define PHY_CFG1_EQLZR		0x0100	/* 1=Rx Equalizer Disabled */
+#define PHY_CFG1_CABLE		0x0080	/* 1=STP(150ohm), 0=UTP(100ohm) */
+#define PHY_CFG1_RLVL0		0x0040	/* 1=Rx Squelch level reduced by 4.5db */
+#define PHY_CFG1_TLVL_SHIFT	2	/* Transmit Output Level Adjust */
+#define PHY_CFG1_TLVL_MASK	0x003C
+#define PHY_CFG1_TRF_MASK	0x0003	/* Transmitter Rise/Fall time */
+
+
+/* PHY Configuration Register 2 */
+#define PHY_CFG2_REG		0x11
+#define PHY_CFG2_APOLDIS	0x0020	/* 1=Auto Polarity Correction disabled */
+#define PHY_CFG2_JABDIS		0x0010	/* 1=Jabber disabled */
+#define PHY_CFG2_MREG		0x0008	/* 1=Multiple register access (MII mgt) */
+#define PHY_CFG2_INTMDIO	0x0004	/* 1=Interrupt signaled with MDIO pulseo */
+
+/* PHY Status Output (and Interrupt status) Register */
+#define PHY_INT_REG		0x12	/* Status Output (Interrupt Status) */
+#define PHY_INT_INT		0x8000	/* 1=bits have changed since last read */
+#define	PHY_INT_LNKFAIL		0x4000	/* 1=Link Not detected */
+#define PHY_INT_LOSSSYNC	0x2000	/* 1=Descrambler has lost sync */
+#define PHY_INT_CWRD		0x1000	/* 1=Invalid 4B5B code detected on rx */
+#define PHY_INT_SSD		0x0800	/* 1=No Start Of Stream detected on rx */
+#define PHY_INT_ESD		0x0400	/* 1=No End Of Stream detected on rx */
+#define PHY_INT_RPOL		0x0200	/* 1=Reverse Polarity detected */
+#define PHY_INT_JAB		0x0100	/* 1=Jabber detected */
+#define PHY_INT_SPDDET		0x0080	/* 1=100Base-TX mode, 0=10Base-T mode */
+#define PHY_INT_DPLXDET		0x0040	/* 1=Device in Full Duplex */
+
+/* PHY Interrupt/Status Mask Register */
+#define PHY_MASK_REG		0x13	/* Interrupt Mask */
+/* Uses the same bit definitions as PHY_INT_REG */
+
+
+/*-------------------------------------------------------------------------
+ .  I define some macros to make it easier to do somewhat common
+ . or slightly complicated, repeated tasks.
+ --------------------------------------------------------------------------*/
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x)  { SMC_outw( x, BANK_SELECT ); }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( IM_REG );\
+		mask |= (x);\
+		SMC_outb( mask, IM_REG ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( IM_REG );\
+		mask &= ~(x);\
+		SMC_outb( mask, IM_REG ); \
+}
+
+/*----------------------------------------------------------------------
+ . Define the interrupts that I want to receive from the card
+ .
+ . I want:
+ .  IM_EPH_INT, for nasty errors
+ .  IM_RCV_INT, for happy received packets
+ .  IM_RX_OVRN_INT, because I have to kick the receiver
+ .  IM_MDINT, for PHY Register 18 Status Changes
+ --------------------------------------------------------------------------*/
+#define SMC_INTERRUPT_MASK   (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \
+	IM_MDINT)
+
+#endif  /* _SMC_91111_H_ */
diff --git a/drivers/net/tigon3.c b/drivers/net/tigon3.c
new file mode 100644
index 0000000..5f6a4ec
--- /dev/null
+++ b/drivers/net/tigon3.c
@@ -0,0 +1,5699 @@
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/******************************************************************************/
+#include <common.h>
+#include <asm/types.h>
+#if defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI) && \
+	defined(CONFIG_TIGON3)
+#ifdef CONFIG_BMW
+#include <mpc824x.h>
+#endif
+#include <malloc.h>
+#include <linux/byteorder/big_endian.h>
+#include "bcm570x_mm.h"
+
+#define EMBEDDED 1
+/******************************************************************************/
+/* Local functions. */
+/******************************************************************************/
+
+LM_STATUS LM_Abort (PLM_DEVICE_BLOCK pDevice);
+LM_STATUS LM_QueueRxPackets (PLM_DEVICE_BLOCK pDevice);
+
+static LM_STATUS LM_TranslateRequestedMediaType (LM_REQUESTED_MEDIA_TYPE
+						 RequestedMediaType,
+						 PLM_MEDIA_TYPE pMediaType,
+						 PLM_LINE_SPEED pLineSpeed,
+						 PLM_DUPLEX_MODE pDuplexMode);
+
+static LM_STATUS LM_InitBcm540xPhy (PLM_DEVICE_BLOCK pDevice);
+
+__inline static LM_VOID LM_ServiceRxInterrupt (PLM_DEVICE_BLOCK pDevice);
+__inline static LM_VOID LM_ServiceTxInterrupt (PLM_DEVICE_BLOCK pDevice);
+
+static LM_STATUS LM_ForceAutoNegBcm540xPhy (PLM_DEVICE_BLOCK pDevice,
+					    LM_REQUESTED_MEDIA_TYPE
+					    RequestedMediaType);
+static LM_STATUS LM_ForceAutoNeg (PLM_DEVICE_BLOCK pDevice,
+				  LM_REQUESTED_MEDIA_TYPE RequestedMediaType);
+static LM_UINT32 GetPhyAdFlowCntrlSettings (PLM_DEVICE_BLOCK pDevice);
+STATIC LM_STATUS LM_SetFlowControl (PLM_DEVICE_BLOCK pDevice,
+				    LM_UINT32 LocalPhyAd,
+				    LM_UINT32 RemotePhyAd);
+#if INCLUDE_TBI_SUPPORT
+STATIC LM_STATUS LM_SetupFiberPhy (PLM_DEVICE_BLOCK pDevice);
+STATIC LM_STATUS LM_InitBcm800xPhy (PLM_DEVICE_BLOCK pDevice);
+#endif
+STATIC LM_STATUS LM_SetupCopperPhy (PLM_DEVICE_BLOCK pDevice);
+STATIC PLM_ADAPTER_INFO LM_GetAdapterInfoBySsid (LM_UINT16 Svid,
+						 LM_UINT16 Ssid);
+STATIC LM_STATUS LM_DmaTest (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt,
+			     LM_PHYSICAL_ADDRESS BufferPhy,
+			     LM_UINT32 BufferSize);
+STATIC LM_STATUS LM_HaltCpu (PLM_DEVICE_BLOCK pDevice, LM_UINT32 cpu_number);
+STATIC LM_STATUS LM_ResetChip (PLM_DEVICE_BLOCK pDevice);
+STATIC LM_STATUS LM_Test4GBoundary (PLM_DEVICE_BLOCK pDevice,
+				    PLM_PACKET pPacket, PT3_SND_BD pSendBd);
+
+/******************************************************************************/
+/* External functions. */
+/******************************************************************************/
+
+LM_STATUS LM_LoadRlsFirmware (PLM_DEVICE_BLOCK pDevice);
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_UINT32 LM_RegRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register)
+{
+	LM_UINT32 Value32;
+
+#if PCIX_TARGET_WORKAROUND
+	MM_ACQUIRE_UNDI_LOCK (pDevice);
+#endif
+	MM_WriteConfig32 (pDevice, T3_PCI_REG_ADDR_REG, Register);
+	MM_ReadConfig32 (pDevice, T3_PCI_REG_DATA_REG, &Value32);
+#if PCIX_TARGET_WORKAROUND
+	MM_RELEASE_UNDI_LOCK (pDevice);
+#endif
+
+	return Value32;
+}				/* LM_RegRdInd */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_VOID
+LM_RegWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register, LM_UINT32 Value32)
+{
+
+#if PCIX_TARGET_WORKAROUND
+	MM_ACQUIRE_UNDI_LOCK (pDevice);
+#endif
+	MM_WriteConfig32 (pDevice, T3_PCI_REG_ADDR_REG, Register);
+	MM_WriteConfig32 (pDevice, T3_PCI_REG_DATA_REG, Value32);
+#if PCIX_TARGET_WORKAROUND
+	MM_RELEASE_UNDI_LOCK (pDevice);
+#endif
+}				/* LM_RegWrInd */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_UINT32 LM_MemRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr)
+{
+	LM_UINT32 Value32;
+
+	MM_ACQUIRE_UNDI_LOCK (pDevice);
+#ifdef BIG_ENDIAN_HOST
+	MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr);
+	Value32 = REG_RD (pDevice, PciCfg.MemWindowData);
+	/*    Value32 = REG_RD(pDevice,uIntMem.Mbuf[(MemAddr & 0x7fff)/4]); */
+#else
+	MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr);
+	MM_ReadConfig32 (pDevice, T3_PCI_MEM_WIN_DATA_REG, &Value32);
+#endif
+	MM_RELEASE_UNDI_LOCK (pDevice);
+
+	return Value32;
+}				/* LM_MemRdInd */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_VOID
+LM_MemWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr, LM_UINT32 Value32)
+{
+	MM_ACQUIRE_UNDI_LOCK (pDevice);
+#ifdef BIG_ENDIAN_HOST
+	REG_WR (pDevice, PciCfg.MemWindowBaseAddr, MemAddr);
+	REG_WR (pDevice, uIntMem.Mbuf[(MemAddr & 0x7fff) / 4], Value32);
+#else
+	MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr);
+	MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_DATA_REG, Value32);
+#endif
+	MM_RELEASE_UNDI_LOCK (pDevice);
+}				/* LM_MemWrInd */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_QueueRxPackets (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_STATUS Lmstatus;
+	PLM_PACKET pPacket;
+	PT3_RCV_BD pRcvBd;
+	LM_UINT32 StdBdAdded = 0;
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	LM_UINT32 JumboBdAdded = 0;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	Lmstatus = LM_STATUS_SUCCESS;
+
+	pPacket = (PLM_PACKET) QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
+	while (pPacket) {
+		switch (pPacket->u.Rx.RcvProdRing) {
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+		case T3_JUMBO_RCV_PROD_RING:	/* Jumbo Receive Ring. */
+			/* Initialize the buffer descriptor. */
+			pRcvBd =
+			    &pDevice->pRxJumboBdVirt[pDevice->RxJumboProdIdx];
+			pRcvBd->Flags =
+			    RCV_BD_FLAG_END | RCV_BD_FLAG_JUMBO_RING;
+			pRcvBd->Len = (LM_UINT16) pDevice->RxJumboBufferSize;
+
+			/* Initialize the receive buffer pointer */
+#if 0				/* Jimmy, deleted in new */
+			pRcvBd->HostAddr.Low = pPacket->u.Rx.RxBufferPhy.Low;
+			pRcvBd->HostAddr.High = pPacket->u.Rx.RxBufferPhy.High;
+#endif
+			MM_MapRxDma (pDevice, pPacket, &pRcvBd->HostAddr);
+
+			/* The opaque field may point to an offset from a fix addr. */
+			pRcvBd->Opaque = (LM_UINT32) (MM_UINT_PTR (pPacket) -
+						      MM_UINT_PTR (pDevice->
+								   pPacketDescBase));
+
+			/* Update the producer index. */
+			pDevice->RxJumboProdIdx =
+			    (pDevice->RxJumboProdIdx +
+			     1) & T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK;
+
+			JumboBdAdded++;
+			break;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+		case T3_STD_RCV_PROD_RING:	/* Standard Receive Ring. */
+			/* Initialize the buffer descriptor. */
+			pRcvBd = &pDevice->pRxStdBdVirt[pDevice->RxStdProdIdx];
+			pRcvBd->Flags = RCV_BD_FLAG_END;
+			pRcvBd->Len = MAX_STD_RCV_BUFFER_SIZE;
+
+			/* Initialize the receive buffer pointer */
+#if 0				/* Jimmy, deleted in new replaced with MM_MapRxDma */
+			pRcvBd->HostAddr.Low = pPacket->u.Rx.RxBufferPhy.Low;
+			pRcvBd->HostAddr.High = pPacket->u.Rx.RxBufferPhy.High;
+#endif
+			MM_MapRxDma (pDevice, pPacket, &pRcvBd->HostAddr);
+
+			/* The opaque field may point to an offset from a fix addr. */
+			pRcvBd->Opaque = (LM_UINT32) (MM_UINT_PTR (pPacket) -
+						      MM_UINT_PTR (pDevice->
+								   pPacketDescBase));
+
+			/* Update the producer index. */
+			pDevice->RxStdProdIdx = (pDevice->RxStdProdIdx + 1) &
+			    T3_STD_RCV_RCB_ENTRY_COUNT_MASK;
+
+			StdBdAdded++;
+			break;
+
+		case T3_UNKNOWN_RCV_PROD_RING:
+		default:
+			Lmstatus = LM_STATUS_FAILURE;
+			break;
+		}		/* switch */
+
+		/* Bail out if there is any error. */
+		if (Lmstatus != LM_STATUS_SUCCESS) {
+			break;
+		}
+
+		pPacket =
+		    (PLM_PACKET) QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
+	}			/* while */
+
+	wmb ();
+	/* Update the procedure index. */
+	if (StdBdAdded) {
+		MB_REG_WR (pDevice, Mailbox.RcvStdProdIdx.Low,
+			   pDevice->RxStdProdIdx);
+	}
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	if (JumboBdAdded) {
+		MB_REG_WR (pDevice, Mailbox.RcvJumboProdIdx.Low,
+			   pDevice->RxJumboProdIdx);
+	}
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	return Lmstatus;
+}				/* LM_QueueRxPackets */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+STATIC LM_VOID LM_NvramInit (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+	/* Intialize clock period and state machine. */
+	Value32 = SEEPROM_ADDR_CLK_PERD (SEEPROM_CLOCK_PERIOD) |
+	    SEEPROM_ADDR_FSM_RESET;
+	REG_WR (pDevice, Grc.EepromAddr, Value32);
+
+	for (j = 0; j < 100; j++) {
+		MM_Wait (10);
+	}
+
+	/* Serial eeprom access using the Grc.EepromAddr/EepromData registers. */
+	Value32 = REG_RD (pDevice, Grc.LocalCtrl);
+	REG_WR (pDevice, Grc.LocalCtrl,
+		Value32 | GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM);
+
+	/* Set the 5701 compatibility mode if we are using EEPROM. */
+	if (T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5700 &&
+	    T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5701) {
+		Value32 = REG_RD (pDevice, Nvram.Config1);
+		if ((Value32 & FLASH_INTERFACE_ENABLE) == 0) {
+			/* Use the new interface to read EEPROM. */
+			Value32 &= ~FLASH_COMPAT_BYPASS;
+
+			REG_WR (pDevice, Nvram.Config1, Value32);
+		}
+	}
+}				/* LM_NvRamInit */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+STATIC LM_STATUS
+LM_EepromRead (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 * pData)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 Addr;
+	LM_UINT32 Dev;
+	LM_UINT32 j;
+
+	if (Offset > SEEPROM_CHIP_SIZE) {
+		return LM_STATUS_FAILURE;
+	}
+
+	Dev = Offset / SEEPROM_CHIP_SIZE;
+	Addr = Offset % SEEPROM_CHIP_SIZE;
+
+	Value32 = REG_RD (pDevice, Grc.EepromAddr);
+	Value32 &= ~(SEEPROM_ADDR_ADDRESS_MASK | SEEPROM_ADDR_DEV_ID_MASK |
+		     SEEPROM_ADDR_RW_MASK);
+	REG_WR (pDevice, Grc.EepromAddr, Value32 | SEEPROM_ADDR_DEV_ID (Dev) |
+		SEEPROM_ADDR_ADDRESS (Addr) | SEEPROM_ADDR_START |
+		SEEPROM_ADDR_READ);
+
+	for (j = 0; j < 1000; j++) {
+		Value32 = REG_RD (pDevice, Grc.EepromAddr);
+		if (Value32 & SEEPROM_ADDR_COMPLETE) {
+			break;
+		}
+		MM_Wait (10);
+	}
+
+	if (Value32 & SEEPROM_ADDR_COMPLETE) {
+		Value32 = REG_RD (pDevice, Grc.EepromData);
+		*pData = Value32;
+
+		return LM_STATUS_SUCCESS;
+	}
+
+	return LM_STATUS_FAILURE;
+}				/* LM_EepromRead */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+STATIC LM_STATUS
+LM_NvramRead (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 * pData)
+{
+	LM_UINT32 Value32;
+	LM_STATUS Status;
+	LM_UINT32 j;
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+	    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+		Status = LM_EepromRead (pDevice, Offset, pData);
+	} else {
+		/* Determine if we have flash or EEPROM. */
+		Value32 = REG_RD (pDevice, Nvram.Config1);
+		if (Value32 & FLASH_INTERFACE_ENABLE) {
+			if (Value32 & FLASH_SSRAM_BUFFERRED_MODE) {
+				Offset = ((Offset / BUFFERED_FLASH_PAGE_SIZE) <<
+					  BUFFERED_FLASH_PAGE_POS) +
+				    (Offset % BUFFERED_FLASH_PAGE_SIZE);
+			}
+		}
+
+		REG_WR (pDevice, Nvram.SwArb, SW_ARB_REQ_SET1);
+		for (j = 0; j < 1000; j++) {
+			if (REG_RD (pDevice, Nvram.SwArb) & SW_ARB_GNT1) {
+				break;
+			}
+			MM_Wait (20);
+		}
+		if (j == 1000) {
+			return LM_STATUS_FAILURE;
+		}
+
+		/* Read from flash or EEPROM with the new 5703/02 interface. */
+		REG_WR (pDevice, Nvram.Addr, Offset & NVRAM_ADDRESS_MASK);
+
+		REG_WR (pDevice, Nvram.Cmd, NVRAM_CMD_RD | NVRAM_CMD_DO_IT |
+			NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+
+		/* Wait for the done bit to clear. */
+		for (j = 0; j < 500; j++) {
+			MM_Wait (10);
+
+			Value32 = REG_RD (pDevice, Nvram.Cmd);
+			if (!(Value32 & NVRAM_CMD_DONE)) {
+				break;
+			}
+		}
+
+		/* Wait for the done bit. */
+		if (!(Value32 & NVRAM_CMD_DONE)) {
+			for (j = 0; j < 500; j++) {
+				MM_Wait (10);
+
+				Value32 = REG_RD (pDevice, Nvram.Cmd);
+				if (Value32 & NVRAM_CMD_DONE) {
+					MM_Wait (10);
+
+					*pData =
+					    REG_RD (pDevice, Nvram.ReadData);
+
+					/* Change the endianess. */
+					*pData =
+					    ((*pData & 0xff) << 24) |
+					    ((*pData & 0xff00) << 8) |
+					    ((*pData & 0xff0000) >> 8) |
+					    ((*pData >> 24) & 0xff);
+
+					break;
+				}
+			}
+		}
+
+		REG_WR (pDevice, Nvram.SwArb, SW_ARB_REQ_CLR1);
+		if (Value32 & NVRAM_CMD_DONE) {
+			Status = LM_STATUS_SUCCESS;
+		} else {
+			Status = LM_STATUS_FAILURE;
+		}
+	}
+
+	return Status;
+}				/* LM_NvramRead */
+
+STATIC void LM_ReadVPD (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Vpd_arr[256 / 4];
+	LM_UINT8 *Vpd = (LM_UINT8 *) & Vpd_arr[0];
+	LM_UINT32 *Vpd_dptr = &Vpd_arr[0];
+	LM_UINT32 Value32;
+	unsigned int j;
+
+	/* Read PN from VPD */
+	for (j = 0; j < 256; j += 4, Vpd_dptr++) {
+		if (LM_NvramRead (pDevice, 0x100 + j, &Value32) !=
+		    LM_STATUS_SUCCESS) {
+			printf ("BCM570x: LM_ReadVPD: VPD read failed"
+				" (no EEPROM onboard)\n");
+			return;
+		}
+		*Vpd_dptr = cpu_to_le32 (Value32);
+	}
+	for (j = 0; j < 256;) {
+		unsigned int Vpd_r_len;
+		unsigned int Vpd_r_end;
+
+		if ((Vpd[j] == 0x82) || (Vpd[j] == 0x91)) {
+			j = j + 3 + Vpd[j + 1] + (Vpd[j + 2] << 8);
+		} else if (Vpd[j] == 0x90) {
+			Vpd_r_len = Vpd[j + 1] + (Vpd[j + 2] << 8);
+			j += 3;
+			Vpd_r_end = Vpd_r_len + j;
+			while (j < Vpd_r_end) {
+				if ((Vpd[j] == 'P') && (Vpd[j + 1] == 'N')) {
+					unsigned int len = Vpd[j + 2];
+
+					if (len <= 24) {
+						memcpy (pDevice->PartNo,
+							&Vpd[j + 3], len);
+					}
+					break;
+				} else {
+					if (Vpd[j + 2] == 0) {
+						break;
+					}
+					j = j + Vpd[j + 2];
+				}
+			}
+			break;
+		} else {
+			break;
+		}
+	}
+}
+
+STATIC void LM_ReadBootCodeVersion (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32, offset, ver_offset;
+	int i;
+
+	if (LM_NvramRead (pDevice, 0x0, &Value32) != LM_STATUS_SUCCESS)
+		return;
+	if (Value32 != 0xaa559966)
+		return;
+	if (LM_NvramRead (pDevice, 0xc, &offset) != LM_STATUS_SUCCESS)
+		return;
+
+	offset = ((offset & 0xff) << 24) | ((offset & 0xff00) << 8) |
+	    ((offset & 0xff0000) >> 8) | ((offset >> 24) & 0xff);
+	if (LM_NvramRead (pDevice, offset, &Value32) != LM_STATUS_SUCCESS)
+		return;
+	if ((Value32 == 0x0300000e) &&
+	    (LM_NvramRead (pDevice, offset + 4, &Value32) == LM_STATUS_SUCCESS)
+	    && (Value32 == 0)) {
+
+		if (LM_NvramRead (pDevice, offset + 8, &ver_offset) !=
+		    LM_STATUS_SUCCESS)
+			return;
+		ver_offset = ((ver_offset & 0xff0000) >> 8) |
+		    ((ver_offset >> 24) & 0xff);
+		for (i = 0; i < 16; i += 4) {
+			if (LM_NvramRead
+			    (pDevice, offset + ver_offset + i,
+			     &Value32) != LM_STATUS_SUCCESS) {
+				return;
+			}
+			*((LM_UINT32 *) & pDevice->BootCodeVer[i]) =
+			    cpu_to_le32 (Value32);
+		}
+	} else {
+		char c;
+
+		if (LM_NvramRead (pDevice, 0x94, &Value32) != LM_STATUS_SUCCESS)
+			return;
+
+		i = 0;
+		c = ((Value32 & 0xff0000) >> 16);
+
+		if (c < 10) {
+			pDevice->BootCodeVer[i++] = c + '0';
+		} else {
+			pDevice->BootCodeVer[i++] = (c / 10) + '0';
+			pDevice->BootCodeVer[i++] = (c % 10) + '0';
+		}
+		pDevice->BootCodeVer[i++] = '.';
+		c = (Value32 & 0xff000000) >> 24;
+		if (c < 10) {
+			pDevice->BootCodeVer[i++] = c + '0';
+		} else {
+			pDevice->BootCodeVer[i++] = (c / 10) + '0';
+			pDevice->BootCodeVer[i++] = (c % 10) + '0';
+		}
+		pDevice->BootCodeVer[i] = 0;
+	}
+}
+
+STATIC void LM_GetBusSpeed (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 PciState = pDevice->PciState;
+	LM_UINT32 ClockCtrl;
+	char *SpeedStr = "";
+
+	if (PciState & T3_PCI_STATE_32BIT_PCI_BUS) {
+		strcpy (pDevice->BusSpeedStr, "32-bit ");
+	} else {
+		strcpy (pDevice->BusSpeedStr, "64-bit ");
+	}
+	if (PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) {
+		strcat (pDevice->BusSpeedStr, "PCI ");
+		if (PciState & T3_PCI_STATE_HIGH_BUS_SPEED) {
+			SpeedStr = "66MHz";
+		} else {
+			SpeedStr = "33MHz";
+		}
+	} else {
+		strcat (pDevice->BusSpeedStr, "PCIX ");
+		if (pDevice->BondId == GRC_MISC_BD_ID_5704CIOBE) {
+			SpeedStr = "133MHz";
+		} else {
+			ClockCtrl = REG_RD (pDevice, PciCfg.ClockCtrl) & 0x1f;
+			switch (ClockCtrl) {
+			case 0:
+				SpeedStr = "33MHz";
+				break;
+
+			case 2:
+				SpeedStr = "50MHz";
+				break;
+
+			case 4:
+				SpeedStr = "66MHz";
+				break;
+
+			case 6:
+				SpeedStr = "100MHz";
+				break;
+
+			case 7:
+				SpeedStr = "133MHz";
+				break;
+			}
+		}
+	}
+	strcat (pDevice->BusSpeedStr, SpeedStr);
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine initializes default parameters and reads the PCI           */
+/*    configurations.                                                         */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_GetAdapterInfo (PLM_DEVICE_BLOCK pDevice)
+{
+	PLM_ADAPTER_INFO pAdapterInfo;
+	LM_UINT32 Value32;
+	LM_STATUS Status;
+	LM_UINT32 j;
+	LM_UINT32 EeSigFound;
+	LM_UINT32 EePhyTypeSerdes = 0;
+	LM_UINT32 EePhyLedMode = 0;
+	LM_UINT32 EePhyId = 0;
+
+	/* Get Device Id and Vendor Id */
+	Status = MM_ReadConfig32 (pDevice, PCI_VENDOR_ID_REG, &Value32);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+	pDevice->PciVendorId = (LM_UINT16) Value32;
+	pDevice->PciDeviceId = (LM_UINT16) (Value32 >> 16);
+
+	/* If we are not getting the write adapter, exit. */
+	if ((Value32 != T3_PCI_ID_BCM5700) &&
+	    (Value32 != T3_PCI_ID_BCM5701) &&
+	    (Value32 != T3_PCI_ID_BCM5702) &&
+	    (Value32 != T3_PCI_ID_BCM5702x) &&
+	    (Value32 != T3_PCI_ID_BCM5702FE) &&
+	    (Value32 != T3_PCI_ID_BCM5703) &&
+	    (Value32 != T3_PCI_ID_BCM5703x) && (Value32 != T3_PCI_ID_BCM5704)) {
+		return LM_STATUS_FAILURE;
+	}
+
+	Status = MM_ReadConfig32 (pDevice, PCI_REV_ID_REG, &Value32);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+	pDevice->PciRevId = (LM_UINT8) Value32;
+
+	/* Get IRQ. */
+	Status = MM_ReadConfig32 (pDevice, PCI_INT_LINE_REG, &Value32);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+	pDevice->Irq = (LM_UINT8) Value32;
+
+	/* Get interrupt pin. */
+	pDevice->IntPin = (LM_UINT8) (Value32 >> 8);
+
+	/* Get chip revision id. */
+	Status = MM_ReadConfig32 (pDevice, T3_PCI_MISC_HOST_CTRL_REG, &Value32);
+	pDevice->ChipRevId = Value32 >> 16;
+
+	/* Get subsystem vendor. */
+	Status =
+	    MM_ReadConfig32 (pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, &Value32);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+	pDevice->SubsystemVendorId = (LM_UINT16) Value32;
+
+	/* Get PCI subsystem id. */
+	pDevice->SubsystemId = (LM_UINT16) (Value32 >> 16);
+
+	/* Get the cache line size. */
+	MM_ReadConfig32 (pDevice, PCI_CACHE_LINE_SIZE_REG, &Value32);
+	pDevice->CacheLineSize = (LM_UINT8) Value32;
+	pDevice->SavedCacheLineReg = Value32;
+
+	if (pDevice->ChipRevId != T3_CHIP_ID_5703_A1 &&
+	    pDevice->ChipRevId != T3_CHIP_ID_5703_A2 &&
+	    pDevice->ChipRevId != T3_CHIP_ID_5704_A0) {
+		pDevice->UndiFix = FALSE;
+	}
+#if !PCIX_TARGET_WORKAROUND
+	pDevice->UndiFix = FALSE;
+#endif
+	/* Map the memory base to system address space. */
+	if (!pDevice->UndiFix) {
+		Status = MM_MapMemBase (pDevice);
+		if (Status != LM_STATUS_SUCCESS) {
+			return Status;
+		}
+		/* Initialize the memory view pointer. */
+		pDevice->pMemView = (PT3_STD_MEM_MAP) pDevice->pMappedMemBase;
+	}
+#if PCIX_TARGET_WORKAROUND
+	/* store whether we are in PCI are PCI-X mode */
+	pDevice->EnablePciXFix = FALSE;
+
+	MM_ReadConfig32 (pDevice, T3_PCI_STATE_REG, &Value32);
+	if ((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0) {
+		/* Enable PCI-X workaround only if we are running on 5700 BX. */
+		if (T3_CHIP_REV (pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) {
+			pDevice->EnablePciXFix = TRUE;
+		}
+	}
+	if (pDevice->UndiFix) {
+		pDevice->EnablePciXFix = TRUE;
+	}
+#endif
+	/* Bx bug: due to the "byte_enable bug" in PCI-X mode, the power */
+	/* management register may be clobbered which may cause the */
+	/* BCM5700 to go into D3 state.  While in this state, we will */
+	/* not have memory mapped register access.  As a workaround, we */
+	/* need to restore the device to D0 state. */
+	MM_ReadConfig32 (pDevice, T3_PCI_PM_STATUS_CTRL_REG, &Value32);
+	Value32 |= T3_PM_PME_ASSERTED;
+	Value32 &= ~T3_PM_POWER_STATE_MASK;
+	Value32 |= T3_PM_POWER_STATE_D0;
+	MM_WriteConfig32 (pDevice, T3_PCI_PM_STATUS_CTRL_REG, Value32);
+
+	/* read the current PCI command word */
+	MM_ReadConfig32 (pDevice, PCI_COMMAND_REG, &Value32);
+
+	/* Make sure bus-mastering is enabled. */
+	Value32 |= PCI_BUSMASTER_ENABLE;
+
+#if PCIX_TARGET_WORKAROUND
+	/* if we are in PCI-X mode, also make sure mem-mapping and SERR#/PERR#
+	   are enabled */
+	if (pDevice->EnablePciXFix == TRUE) {
+		Value32 |= (PCI_MEM_SPACE_ENABLE | PCI_SYSTEM_ERROR_ENABLE |
+			    PCI_PARITY_ERROR_ENABLE);
+	}
+	if (pDevice->UndiFix) {
+		Value32 &= ~PCI_MEM_SPACE_ENABLE;
+	}
+#endif
+
+	if (pDevice->EnableMWI) {
+		Value32 |= PCI_MEMORY_WRITE_INVALIDATE;
+	} else {
+		Value32 &= (~PCI_MEMORY_WRITE_INVALIDATE);
+	}
+
+	/* Error out if mem-mapping is NOT enabled for PCI systems */
+	if (!(Value32 | PCI_MEM_SPACE_ENABLE)) {
+		return LM_STATUS_FAILURE;
+	}
+
+	/* save the value we are going to write into the PCI command word */
+	pDevice->PciCommandStatusWords = Value32;
+
+	Status = MM_WriteConfig32 (pDevice, PCI_COMMAND_REG, Value32);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+
+	/* Set power state to D0. */
+	LM_SetPowerState (pDevice, LM_POWER_STATE_D0);
+
+#ifdef BIG_ENDIAN_PCI
+	pDevice->MiscHostCtrl =
+	    MISC_HOST_CTRL_MASK_PCI_INT |
+	    MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS |
+	    MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP |
+	    MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW;
+#else				/* No CPU Swap modes for PCI IO */
+
+	/* Setup the mode registers. */
+	pDevice->MiscHostCtrl =
+	    MISC_HOST_CTRL_MASK_PCI_INT |
+	    MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP |
+#ifdef BIG_ENDIAN_HOST
+	    MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP |
+#endif				/* BIG_ENDIAN_HOST */
+	    MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS |
+	    MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW;
+#endif				/* !BIG_ENDIAN_PCI */
+
+	/* write to PCI misc host ctr first in order to enable indirect accesses */
+	MM_WriteConfig32 (pDevice, T3_PCI_MISC_HOST_CTRL_REG,
+			  pDevice->MiscHostCtrl);
+
+	REG_WR (pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl);
+
+#ifdef BIG_ENDIAN_PCI
+	Value32 = GRC_MODE_WORD_SWAP_DATA | GRC_MODE_WORD_SWAP_NON_FRAME_DATA;
+#else
+/* No CPU Swap modes for PCI IO */
+#ifdef BIG_ENDIAN_HOST
+	Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_WORD_SWAP_NON_FRAME_DATA;
+#else
+	Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA;
+#endif
+#endif				/* !BIG_ENDIAN_PCI */
+
+	REG_WR (pDevice, Grc.Mode, Value32);
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		REG_WR (pDevice, Grc.LocalCtrl,
+			GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 |
+			GRC_MISC_LOCAL_CTRL_GPIO_OE1);
+	}
+	MM_Wait (40);
+
+	/* Enable indirect memory access */
+	REG_WR (pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE);
+
+	if (REG_RD (pDevice, PciCfg.ClockCtrl) & T3_PCI_44MHZ_CORE_CLOCK) {
+		REG_WR (pDevice, PciCfg.ClockCtrl, T3_PCI_44MHZ_CORE_CLOCK |
+			T3_PCI_SELECT_ALTERNATE_CLOCK);
+		REG_WR (pDevice, PciCfg.ClockCtrl,
+			T3_PCI_SELECT_ALTERNATE_CLOCK);
+		MM_Wait (40);	/* required delay is 27usec */
+	}
+	REG_WR (pDevice, PciCfg.ClockCtrl, 0);
+	REG_WR (pDevice, PciCfg.MemWindowBaseAddr, 0);
+
+#if PCIX_TARGET_WORKAROUND
+	MM_ReadConfig32 (pDevice, T3_PCI_STATE_REG, &Value32);
+	if ((pDevice->EnablePciXFix == FALSE) &&
+	    ((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0)) {
+		if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5701_B0 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5701_B2 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5701_B5) {
+			__raw_writel (0,
+				      &(pDevice->pMemView->uIntMem.
+					MemBlock32K[0x300]));
+			__raw_writel (0,
+				      &(pDevice->pMemView->uIntMem.
+					MemBlock32K[0x301]));
+			__raw_writel (0xffffffff,
+				      &(pDevice->pMemView->uIntMem.
+					MemBlock32K[0x301]));
+			if (__raw_readl
+			    (&(pDevice->pMemView->uIntMem.MemBlock32K[0x300])))
+			{
+				pDevice->EnablePciXFix = TRUE;
+			}
+		}
+	}
+#endif
+#if 1
+	/*
+	 *  This code was at the beginning of else block below, but that's
+	 *  a bug if node address in shared memory.
+	 */
+	MM_Wait (50);
+	LM_NvramInit (pDevice);
+#endif
+	/* Get the node address.  First try to get in from the shared memory. */
+	/* If the signature is not present, then get it from the NVRAM. */
+	Value32 = MEM_RD_OFFSET (pDevice, T3_MAC_ADDR_HIGH_MAILBOX);
+	if ((Value32 >> 16) == 0x484b) {
+
+		pDevice->NodeAddress[0] = (LM_UINT8) (Value32 >> 8);
+		pDevice->NodeAddress[1] = (LM_UINT8) Value32;
+
+		Value32 = MEM_RD_OFFSET (pDevice, T3_MAC_ADDR_LOW_MAILBOX);
+
+		pDevice->NodeAddress[2] = (LM_UINT8) (Value32 >> 24);
+		pDevice->NodeAddress[3] = (LM_UINT8) (Value32 >> 16);
+		pDevice->NodeAddress[4] = (LM_UINT8) (Value32 >> 8);
+		pDevice->NodeAddress[5] = (LM_UINT8) Value32;
+
+		Status = LM_STATUS_SUCCESS;
+	} else {
+		Status = LM_NvramRead (pDevice, 0x7c, &Value32);
+		if (Status == LM_STATUS_SUCCESS) {
+			pDevice->NodeAddress[0] = (LM_UINT8) (Value32 >> 16);
+			pDevice->NodeAddress[1] = (LM_UINT8) (Value32 >> 24);
+
+			Status = LM_NvramRead (pDevice, 0x80, &Value32);
+
+			pDevice->NodeAddress[2] = (LM_UINT8) Value32;
+			pDevice->NodeAddress[3] = (LM_UINT8) (Value32 >> 8);
+			pDevice->NodeAddress[4] = (LM_UINT8) (Value32 >> 16);
+			pDevice->NodeAddress[5] = (LM_UINT8) (Value32 >> 24);
+		}
+	}
+
+	/* Assign a default address. */
+	if (Status != LM_STATUS_SUCCESS) {
+#ifndef EMBEDDED
+		printk (KERN_ERR
+			"Cannot get MAC addr from NVRAM. Using default.\n");
+#endif
+		pDevice->NodeAddress[0] = 0x00;
+		pDevice->NodeAddress[1] = 0x10;
+		pDevice->NodeAddress[2] = 0x18;
+		pDevice->NodeAddress[3] = 0x68;
+		pDevice->NodeAddress[4] = 0x61;
+		pDevice->NodeAddress[5] = 0x76;
+	}
+
+	pDevice->PermanentNodeAddress[0] = pDevice->NodeAddress[0];
+	pDevice->PermanentNodeAddress[1] = pDevice->NodeAddress[1];
+	pDevice->PermanentNodeAddress[2] = pDevice->NodeAddress[2];
+	pDevice->PermanentNodeAddress[3] = pDevice->NodeAddress[3];
+	pDevice->PermanentNodeAddress[4] = pDevice->NodeAddress[4];
+	pDevice->PermanentNodeAddress[5] = pDevice->NodeAddress[5];
+
+	/* Initialize the default values. */
+	pDevice->NoTxPseudoHdrChksum = FALSE;
+	pDevice->NoRxPseudoHdrChksum = FALSE;
+	pDevice->NicSendBd = FALSE;
+	pDevice->TxPacketDescCnt = DEFAULT_TX_PACKET_DESC_COUNT;
+	pDevice->RxStdDescCnt = DEFAULT_STD_RCV_DESC_COUNT;
+	pDevice->RxCoalescingTicks = DEFAULT_RX_COALESCING_TICKS;
+	pDevice->TxCoalescingTicks = DEFAULT_TX_COALESCING_TICKS;
+	pDevice->RxMaxCoalescedFrames = DEFAULT_RX_MAX_COALESCED_FRAMES;
+	pDevice->TxMaxCoalescedFrames = DEFAULT_TX_MAX_COALESCED_FRAMES;
+	pDevice->RxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE;
+	pDevice->TxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE;
+	pDevice->RxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE;
+	pDevice->TxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE;
+	pDevice->StatsCoalescingTicks = DEFAULT_STATS_COALESCING_TICKS;
+	pDevice->EnableMWI = FALSE;
+	pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC;
+	pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC;
+	pDevice->DisableAutoNeg = FALSE;
+	pDevice->PhyIntMode = T3_PHY_INT_MODE_AUTO;
+	pDevice->LinkChngMode = T3_LINK_CHNG_MODE_AUTO;
+	pDevice->LedMode = LED_MODE_AUTO;
+	pDevice->ResetPhyOnInit = TRUE;
+	pDevice->DelayPciGrant = TRUE;
+	pDevice->UseTaggedStatus = FALSE;
+	pDevice->OneDmaAtOnce = BAD_DEFAULT_VALUE;
+
+	pDevice->DmaMbufLowMark = T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO;
+	pDevice->RxMacMbufLowMark = T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO;
+	pDevice->MbufHighMark = T3_DEF_MBUF_HIGH_WMARK_JUMBO;
+
+	pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
+	pDevice->TaskOffloadCap = LM_TASK_OFFLOAD_NONE;
+	pDevice->FlowControlCap = LM_FLOW_CONTROL_AUTO_PAUSE;
+	pDevice->EnableTbi = FALSE;
+#if INCLUDE_TBI_SUPPORT
+	pDevice->PollTbiLink = BAD_DEFAULT_VALUE;
+#endif
+
+	switch (T3_ASIC_REV (pDevice->ChipRevId)) {
+	case T3_ASIC_REV_5704:
+		pDevice->MbufBase = T3_NIC_MBUF_POOL_ADDR;
+		pDevice->MbufSize = T3_NIC_MBUF_POOL_SIZE64;
+		break;
+	default:
+		pDevice->MbufBase = T3_NIC_MBUF_POOL_ADDR;
+		pDevice->MbufSize = T3_NIC_MBUF_POOL_SIZE96;
+		break;
+	}
+
+	pDevice->LinkStatus = LM_STATUS_LINK_DOWN;
+	pDevice->QueueRxPackets = TRUE;
+
+	pDevice->EnableWireSpeed = TRUE;
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* Make this is a known adapter. */
+	pAdapterInfo = LM_GetAdapterInfoBySsid (pDevice->SubsystemVendorId,
+						pDevice->SubsystemId);
+
+	pDevice->BondId = REG_RD (pDevice, Grc.MiscCfg) & GRC_MISC_BD_ID_MASK;
+	if (pDevice->BondId != GRC_MISC_BD_ID_5700 &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5701 &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5702FE &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5703 &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5703S &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5704 &&
+	    pDevice->BondId != GRC_MISC_BD_ID_5704CIOBE) {
+		return LM_STATUS_UNKNOWN_ADAPTER;
+	}
+
+	pDevice->SplitModeEnable = SPLIT_MODE_DISABLE;
+	if ((pDevice->ChipRevId == T3_CHIP_ID_5704_A0) &&
+	    (pDevice->BondId == GRC_MISC_BD_ID_5704CIOBE)) {
+		pDevice->SplitModeEnable = SPLIT_MODE_ENABLE;
+		pDevice->SplitModeMaxReq = SPLIT_MODE_5704_MAX_REQ;
+	}
+
+	/* Get Eeprom info. */
+	Value32 = MEM_RD_OFFSET (pDevice, T3_NIC_DATA_SIG_ADDR);
+	if (Value32 == T3_NIC_DATA_SIG) {
+		EeSigFound = TRUE;
+		Value32 = MEM_RD_OFFSET (pDevice, T3_NIC_DATA_NIC_CFG_ADDR);
+
+		/* Determine PHY type. */
+		switch (Value32 & T3_NIC_CFG_PHY_TYPE_MASK) {
+		case T3_NIC_CFG_PHY_TYPE_COPPER:
+			EePhyTypeSerdes = FALSE;
+			break;
+
+		case T3_NIC_CFG_PHY_TYPE_FIBER:
+			EePhyTypeSerdes = TRUE;
+			break;
+
+		default:
+			EePhyTypeSerdes = FALSE;
+			break;
+		}
+
+		/* Determine PHY led mode. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			switch (Value32 & T3_NIC_CFG_LED_MODE_MASK) {
+			case T3_NIC_CFG_LED_MODE_TRIPLE_SPEED:
+				EePhyLedMode = LED_MODE_THREE_LINK;
+				break;
+
+			case T3_NIC_CFG_LED_MODE_LINK_SPEED:
+				EePhyLedMode = LED_MODE_LINK10;
+				break;
+
+			default:
+				EePhyLedMode = LED_MODE_AUTO;
+				break;
+			}
+		} else {
+			switch (Value32 & T3_NIC_CFG_LED_MODE_MASK) {
+			case T3_NIC_CFG_LED_MODE_OPEN_DRAIN:
+				EePhyLedMode = LED_MODE_OPEN_DRAIN;
+				break;
+
+			case T3_NIC_CFG_LED_MODE_OUTPUT:
+				EePhyLedMode = LED_MODE_OUTPUT;
+				break;
+
+			default:
+				EePhyLedMode = LED_MODE_AUTO;
+				break;
+			}
+		}
+		if (pDevice->ChipRevId == T3_CHIP_ID_5703_A1 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5703_A2) {
+			/* Enable EEPROM write protection. */
+			if (Value32 & T3_NIC_EEPROM_WP) {
+				pDevice->EepromWp = TRUE;
+			}
+		}
+
+		/* Get the PHY Id. */
+		Value32 = MEM_RD_OFFSET (pDevice, T3_NIC_DATA_PHY_ID_ADDR);
+		if (Value32) {
+			EePhyId = (((Value32 & T3_NIC_PHY_ID1_MASK) >> 16) &
+				   PHY_ID1_OUI_MASK) << 10;
+
+			Value32 = Value32 & T3_NIC_PHY_ID2_MASK;
+
+			EePhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) |
+			    (Value32 & PHY_ID2_MODEL_MASK) | (Value32 &
+							      PHY_ID2_REV_MASK);
+		} else {
+			EePhyId = 0;
+		}
+	} else {
+		EeSigFound = FALSE;
+	}
+
+	/* Set the PHY address. */
+	pDevice->PhyAddr = PHY_DEVICE_ID;
+
+	/* Disable auto polling. */
+	pDevice->MiMode = 0xc0000;
+	REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+	MM_Wait (40);
+
+	/* Get the PHY id. */
+	LM_ReadPhy (pDevice, PHY_ID1_REG, &Value32);
+	pDevice->PhyId = (Value32 & PHY_ID1_OUI_MASK) << 10;
+
+	LM_ReadPhy (pDevice, PHY_ID2_REG, &Value32);
+	pDevice->PhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) |
+	    (Value32 & PHY_ID2_MODEL_MASK) | (Value32 & PHY_ID2_REV_MASK);
+
+	/* Set the EnableTbi flag to false if we have a copper PHY. */
+	switch (pDevice->PhyId & PHY_ID_MASK) {
+	case PHY_BCM5400_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM5401_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM5411_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM5701_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM5703_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM5704_PHY_ID:
+		pDevice->EnableTbi = FALSE;
+		break;
+
+	case PHY_BCM8002_PHY_ID:
+		pDevice->EnableTbi = TRUE;
+		break;
+
+	default:
+
+		if (pAdapterInfo) {
+			pDevice->PhyId = pAdapterInfo->PhyId;
+			pDevice->EnableTbi = pAdapterInfo->Serdes;
+		} else if (EeSigFound) {
+			pDevice->PhyId = EePhyId;
+			pDevice->EnableTbi = EePhyTypeSerdes;
+		}
+		break;
+	}
+
+	/* Bail out if we don't know the copper PHY id. */
+	if (UNKNOWN_PHY_ID (pDevice->PhyId) && !pDevice->EnableTbi) {
+		return LM_STATUS_FAILURE;
+	}
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5703) {
+		if ((pDevice->SavedCacheLineReg & 0xff00) < 0x4000) {
+			pDevice->SavedCacheLineReg &= 0xffff00ff;
+			pDevice->SavedCacheLineReg |= 0x4000;
+		}
+	}
+	/* Change driver parameters. */
+	Status = MM_GetConfig (pDevice);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+#if INCLUDE_5701_AX_FIX
+	if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+	    pDevice->ChipRevId == T3_CHIP_ID_5701_B0) {
+		pDevice->ResetPhyOnInit = TRUE;
+	}
+#endif
+
+	/* Save the current phy link status. */
+	if (!pDevice->EnableTbi) {
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+
+		/* If we don't have link reset the PHY. */
+		if (!(Value32 & PHY_STATUS_LINK_PASS)
+		    || pDevice->ResetPhyOnInit) {
+
+			LM_WritePhy (pDevice, PHY_CTRL_REG, PHY_CTRL_PHY_RESET);
+
+			for (j = 0; j < 100; j++) {
+				MM_Wait (10);
+
+				LM_ReadPhy (pDevice, PHY_CTRL_REG, &Value32);
+				if (Value32 && !(Value32 & PHY_CTRL_PHY_RESET)) {
+					MM_Wait (40);
+					break;
+				}
+			}
+
+#if INCLUDE_5701_AX_FIX
+			/* 5701_AX_BX bug:  only advertises 10mb speed. */
+			if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+			    pDevice->ChipRevId == T3_CHIP_ID_5701_B0) {
+
+				Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD |
+				    PHY_AN_AD_10BASET_HALF |
+				    PHY_AN_AD_10BASET_FULL |
+				    PHY_AN_AD_100BASETX_FULL |
+				    PHY_AN_AD_100BASETX_HALF;
+				Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+				LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+				pDevice->advertising = Value32;
+
+				Value32 = BCM540X_AN_AD_1000BASET_HALF |
+				    BCM540X_AN_AD_1000BASET_FULL |
+				    BCM540X_CONFIG_AS_MASTER |
+				    BCM540X_ENABLE_CONFIG_AS_MASTER;
+				LM_WritePhy (pDevice,
+					     BCM540X_1000BASET_CTRL_REG,
+					     Value32);
+				pDevice->advertising1000 = Value32;
+
+				LM_WritePhy (pDevice, PHY_CTRL_REG,
+					     PHY_CTRL_AUTO_NEG_ENABLE |
+					     PHY_CTRL_RESTART_AUTO_NEG);
+			}
+#endif
+			if (T3_ASIC_REV (pDevice->ChipRevId) ==
+			    T3_ASIC_REV_5703) {
+				LM_WritePhy (pDevice, 0x18, 0x0c00);
+				LM_WritePhy (pDevice, 0x17, 0x201f);
+				LM_WritePhy (pDevice, 0x15, 0x2aaa);
+			}
+			if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) {
+				LM_WritePhy (pDevice, 0x1c, 0x8d68);
+				LM_WritePhy (pDevice, 0x1c, 0x8d68);
+			}
+			/* Enable Ethernet@WireSpeed. */
+			if (pDevice->EnableWireSpeed) {
+				LM_WritePhy (pDevice, 0x18, 0x7007);
+				LM_ReadPhy (pDevice, 0x18, &Value32);
+				LM_WritePhy (pDevice, 0x18,
+					     Value32 | BIT_15 | BIT_4);
+			}
+		}
+	}
+
+	/* Turn off tap power management. */
+	if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) {
+		LM_WritePhy (pDevice, BCM5401_AUX_CTRL, 0x0c20);
+		LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012);
+		LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x1804);
+		LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013);
+		LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x1204);
+		LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006);
+		LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0132);
+		LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006);
+		LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0232);
+		LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f);
+		LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0a20);
+
+		MM_Wait (40);
+	}
+#if INCLUDE_TBI_SUPPORT
+	pDevice->IgnoreTbiLinkChange = FALSE;
+
+	if (pDevice->EnableTbi) {
+		pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE;
+		pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY;
+		if ((pDevice->PollTbiLink == BAD_DEFAULT_VALUE) ||
+		    pDevice->DisableAutoNeg) {
+			pDevice->PollTbiLink = FALSE;
+		}
+	} else {
+		pDevice->PollTbiLink = FALSE;
+	}
+#endif				/* INCLUDE_TBI_SUPPORT */
+
+	/* UseTaggedStatus is only valid for 5701 and later. */
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		pDevice->UseTaggedStatus = FALSE;
+
+		pDevice->CoalesceMode = 0;
+	} else {
+		pDevice->CoalesceMode =
+		    HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT |
+		    HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT;
+	}
+
+	/* Set the status block size. */
+	if (T3_CHIP_REV (pDevice->ChipRevId) != T3_CHIP_REV_5700_AX &&
+	    T3_CHIP_REV (pDevice->ChipRevId) != T3_CHIP_REV_5700_BX) {
+		pDevice->CoalesceMode |= HOST_COALESCE_32_BYTE_STATUS_MODE;
+	}
+
+	/* Check the DURING_INT coalescing ticks parameters. */
+	if (pDevice->UseTaggedStatus) {
+		if (pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->RxCoalescingTicksDuringInt =
+			    DEFAULT_RX_COALESCING_TICKS_DURING_INT;
+		}
+
+		if (pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->TxCoalescingTicksDuringInt =
+			    DEFAULT_TX_COALESCING_TICKS_DURING_INT;
+		}
+
+		if (pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->RxMaxCoalescedFramesDuringInt =
+			    DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT;
+		}
+
+		if (pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->TxMaxCoalescedFramesDuringInt =
+			    DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT;
+		}
+	} else {
+		if (pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->RxCoalescingTicksDuringInt = 0;
+		}
+
+		if (pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->TxCoalescingTicksDuringInt = 0;
+		}
+
+		if (pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->RxMaxCoalescedFramesDuringInt = 0;
+		}
+
+		if (pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) {
+			pDevice->TxMaxCoalescedFramesDuringInt = 0;
+		}
+	}
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	if (pDevice->RxMtu <= (MAX_STD_RCV_BUFFER_SIZE - 8 /* CRC */ )) {
+		pDevice->RxJumboDescCnt = 0;
+		if (pDevice->RxMtu <= MAX_ETHERNET_PACKET_SIZE_NO_CRC) {
+			pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC;
+		}
+	} else {
+		pDevice->RxJumboBufferSize =
+		    (pDevice->RxMtu + 8 /* CRC + VLAN */  +
+		     COMMON_CACHE_LINE_SIZE - 1) & ~COMMON_CACHE_LINE_MASK;
+
+		if (pDevice->RxJumboBufferSize > MAX_JUMBO_RCV_BUFFER_SIZE) {
+			pDevice->RxJumboBufferSize =
+			    DEFAULT_JUMBO_RCV_BUFFER_SIZE;
+			pDevice->RxMtu =
+			    pDevice->RxJumboBufferSize - 8 /* CRC + VLAN */ ;
+		}
+		pDevice->TxMtu = pDevice->RxMtu;
+
+	}
+#else
+	pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	pDevice->RxPacketDescCnt =
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	    pDevice->RxJumboDescCnt +
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+	    pDevice->RxStdDescCnt;
+
+	if (pDevice->TxMtu < MAX_ETHERNET_PACKET_SIZE_NO_CRC) {
+		pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC;
+	}
+
+	if (pDevice->TxMtu > MAX_JUMBO_TX_BUFFER_SIZE) {
+		pDevice->TxMtu = MAX_JUMBO_TX_BUFFER_SIZE;
+	}
+
+	/* Configure the proper ways to get link change interrupt. */
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO) {
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+			pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT;
+		} else {
+			pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY;
+		}
+	} else if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		/* Auto-polling does not work on 5700_AX and 5700_BX. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+			pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT;
+		}
+	}
+
+	/* Determine the method to get link change status. */
+	if (pDevice->LinkChngMode == T3_LINK_CHNG_MODE_AUTO) {
+		/* The link status bit in the status block does not work on 5700_AX */
+		/* and 5700_BX chips. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+			pDevice->LinkChngMode =
+			    T3_LINK_CHNG_MODE_USE_STATUS_REG;
+		} else {
+			pDevice->LinkChngMode =
+			    T3_LINK_CHNG_MODE_USE_STATUS_BLOCK;
+		}
+	}
+
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT ||
+	    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG;
+	}
+
+	/* Configure PHY led mode. */
+	if (pDevice->LedMode == LED_MODE_AUTO) {
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			if (pDevice->SubsystemVendorId == T3_SVID_DELL) {
+				pDevice->LedMode = LED_MODE_LINK10;
+			} else {
+				pDevice->LedMode = LED_MODE_THREE_LINK;
+
+				if (EeSigFound && EePhyLedMode != LED_MODE_AUTO) {
+					pDevice->LedMode = EePhyLedMode;
+				}
+			}
+
+			/* bug? 5701 in LINK10 mode does not seem to work when */
+			/* PhyIntMode is LINK_READY. */
+			if (T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5700
+			    &&
+#if INCLUDE_TBI_SUPPORT
+			    pDevice->EnableTbi == FALSE &&
+#endif
+			    pDevice->LedMode == LED_MODE_LINK10) {
+				pDevice->PhyIntMode =
+				    T3_PHY_INT_MODE_MI_INTERRUPT;
+				pDevice->LinkChngMode =
+				    T3_LINK_CHNG_MODE_USE_STATUS_REG;
+			}
+
+			if (pDevice->EnableTbi) {
+				pDevice->LedMode = LED_MODE_THREE_LINK;
+			}
+		} else {
+			if (EeSigFound && EePhyLedMode != LED_MODE_AUTO) {
+				pDevice->LedMode = EePhyLedMode;
+			} else {
+				pDevice->LedMode = LED_MODE_OPEN_DRAIN;
+			}
+		}
+	}
+
+	/* Enable OneDmaAtOnce. */
+	if (pDevice->OneDmaAtOnce == BAD_DEFAULT_VALUE) {
+		pDevice->OneDmaAtOnce = FALSE;
+	}
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+	    pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+	    pDevice->ChipRevId == T3_CHIP_ID_5701_B0 ||
+	    pDevice->ChipRevId == T3_CHIP_ID_5701_B2) {
+		pDevice->WolSpeed = WOL_SPEED_10MB;
+	} else {
+		pDevice->WolSpeed = WOL_SPEED_100MB;
+	}
+
+	/* Offloadings. */
+	pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
+
+	/* Turn off task offloading on Ax. */
+	if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
+		pDevice->TaskOffloadCap &= ~(LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
+					     LM_TASK_OFFLOAD_TX_UDP_CHECKSUM);
+	}
+	pDevice->PciState = REG_RD (pDevice, PciCfg.PciState);
+	LM_ReadVPD (pDevice);
+	LM_ReadBootCodeVersion (pDevice);
+	LM_GetBusSpeed (pDevice);
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_GetAdapterInfo */
+
+STATIC PLM_ADAPTER_INFO LM_GetAdapterInfoBySsid (LM_UINT16 Svid, LM_UINT16 Ssid)
+{
+	static LM_ADAPTER_INFO AdapterArr[] = {
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A6,
+		 PHY_BCM5401_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A5,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700T6,
+		 PHY_BCM8002_PHY_ID, 1},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A9, 0, 1},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T1,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T8,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A7, 0, 1},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A10,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A12,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax1,
+		 PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax2,
+		 PHY_BCM5701_PHY_ID, 0},
+
+		{T3_SVID_3COM, T3_SSID_3COM_3C996T, PHY_BCM5401_PHY_ID, 0},
+		{T3_SVID_3COM, T3_SSID_3COM_3C996BT, PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_3COM, T3_SSID_3COM_3C996SX, 0, 1},
+		{T3_SVID_3COM, T3_SSID_3COM_3C1000T, PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_3COM, T3_SSID_3COM_3C940BR01, PHY_BCM5701_PHY_ID, 0},
+
+		{T3_SVID_DELL, T3_SSID_DELL_VIPER, PHY_BCM5401_PHY_ID, 0},
+		{T3_SVID_DELL, T3_SSID_DELL_JAGUAR, PHY_BCM5401_PHY_ID, 0},
+		{T3_SVID_DELL, T3_SSID_DELL_MERLOT, PHY_BCM5411_PHY_ID, 0},
+		{T3_SVID_DELL, T3_SSID_DELL_SLIM_MERLOT, PHY_BCM5411_PHY_ID, 0},
+
+		{T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE, PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE_2, PHY_BCM5701_PHY_ID,
+		 0},
+		{T3_SVID_COMPAQ, T3_SSID_COMPAQ_CHANGELING, 0, 1},
+		{T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780, PHY_BCM5701_PHY_ID, 0},
+		{T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780_2, PHY_BCM5701_PHY_ID,
+		 0},
+
+	};
+	LM_UINT32 j;
+
+	for (j = 0; j < sizeof (AdapterArr) / sizeof (LM_ADAPTER_INFO); j++) {
+		if (AdapterArr[j].Svid == Svid && AdapterArr[j].Ssid == Ssid) {
+			return &AdapterArr[j];
+		}
+	}
+
+	return NULL;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine sets up receive/transmit buffer descriptions queues.       */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_InitializeAdapter (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_PHYSICAL_ADDRESS MemPhy;
+	PLM_UINT8 pMemVirt;
+	PLM_PACKET pPacket;
+	LM_STATUS Status;
+	LM_UINT32 Size;
+	LM_UINT32 j;
+
+	/* Set power state to D0. */
+	LM_SetPowerState (pDevice, LM_POWER_STATE_D0);
+
+	/* Intialize the queues. */
+	QQ_InitQueue (&pDevice->RxPacketReceivedQ.Container,
+		      MAX_RX_PACKET_DESC_COUNT);
+	QQ_InitQueue (&pDevice->RxPacketFreeQ.Container,
+		      MAX_RX_PACKET_DESC_COUNT);
+
+	QQ_InitQueue (&pDevice->TxPacketFreeQ.Container,
+		      MAX_TX_PACKET_DESC_COUNT);
+	QQ_InitQueue (&pDevice->TxPacketActiveQ.Container,
+		      MAX_TX_PACKET_DESC_COUNT);
+	QQ_InitQueue (&pDevice->TxPacketXmittedQ.Container,
+		      MAX_TX_PACKET_DESC_COUNT);
+
+	/* Allocate shared memory for: status block, the buffers for receive */
+	/* rings -- standard, mini, jumbo, and return rings. */
+	Size = T3_STATUS_BLOCK_SIZE + sizeof (T3_STATS_BLOCK) +
+	    T3_STD_RCV_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD) +
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	    T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD) +
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+	    T3_RCV_RETURN_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD);
+
+	/* Memory for host based Send BD. */
+	if (pDevice->NicSendBd == FALSE) {
+		Size += sizeof (T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT;
+	}
+
+	/* Allocate the memory block. */
+	Status =
+	    MM_AllocateSharedMemory (pDevice, Size, (PLM_VOID) & pMemVirt,
+				     &MemPhy, FALSE);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+
+	/* Program DMA Read/Write */
+	if (pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) {
+		pDevice->DmaReadWriteCtrl = 0x763f000f;
+	} else {
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5704) {
+			pDevice->DmaReadWriteCtrl = 0x761f0000;
+		} else {
+			pDevice->DmaReadWriteCtrl = 0x761b000f;
+		}
+		if (pDevice->ChipRevId == T3_CHIP_ID_5703_A1 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5703_A2) {
+			pDevice->OneDmaAtOnce = TRUE;
+		}
+	}
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5703) {
+		pDevice->DmaReadWriteCtrl &= 0xfffffff0;
+	}
+
+	if (pDevice->OneDmaAtOnce) {
+		pDevice->DmaReadWriteCtrl |= DMA_CTRL_WRITE_ONE_DMA_AT_ONCE;
+	}
+	REG_WR (pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl);
+
+	if (LM_DmaTest (pDevice, pMemVirt, MemPhy, 0x400) != LM_STATUS_SUCCESS) {
+		return LM_STATUS_FAILURE;
+	}
+
+	/* Status block. */
+	pDevice->pStatusBlkVirt = (PT3_STATUS_BLOCK) pMemVirt;
+	pDevice->StatusBlkPhy = MemPhy;
+	pMemVirt += T3_STATUS_BLOCK_SIZE;
+	LM_INC_PHYSICAL_ADDRESS (&MemPhy, T3_STATUS_BLOCK_SIZE);
+
+	/* Statistics block. */
+	pDevice->pStatsBlkVirt = (PT3_STATS_BLOCK) pMemVirt;
+	pDevice->StatsBlkPhy = MemPhy;
+	pMemVirt += sizeof (T3_STATS_BLOCK);
+	LM_INC_PHYSICAL_ADDRESS (&MemPhy, sizeof (T3_STATS_BLOCK));
+
+	/* Receive standard BD buffer. */
+	pDevice->pRxStdBdVirt = (PT3_RCV_BD) pMemVirt;
+	pDevice->RxStdBdPhy = MemPhy;
+
+	pMemVirt += T3_STD_RCV_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD);
+	LM_INC_PHYSICAL_ADDRESS (&MemPhy,
+				 T3_STD_RCV_RCB_ENTRY_COUNT *
+				 sizeof (T3_RCV_BD));
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	/* Receive jumbo BD buffer. */
+	pDevice->pRxJumboBdVirt = (PT3_RCV_BD) pMemVirt;
+	pDevice->RxJumboBdPhy = MemPhy;
+
+	pMemVirt += T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD);
+	LM_INC_PHYSICAL_ADDRESS (&MemPhy,
+				 T3_JUMBO_RCV_RCB_ENTRY_COUNT *
+				 sizeof (T3_RCV_BD));
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* Receive return BD buffer. */
+	pDevice->pRcvRetBdVirt = (PT3_RCV_BD) pMemVirt;
+	pDevice->RcvRetBdPhy = MemPhy;
+
+	pMemVirt += T3_RCV_RETURN_RCB_ENTRY_COUNT * sizeof (T3_RCV_BD);
+	LM_INC_PHYSICAL_ADDRESS (&MemPhy,
+				 T3_RCV_RETURN_RCB_ENTRY_COUNT *
+				 sizeof (T3_RCV_BD));
+
+	/* Set up Send BD. */
+	if (pDevice->NicSendBd == FALSE) {
+		pDevice->pSendBdVirt = (PT3_SND_BD) pMemVirt;
+		pDevice->SendBdPhy = MemPhy;
+
+		pMemVirt += sizeof (T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT;
+		LM_INC_PHYSICAL_ADDRESS (&MemPhy,
+					 sizeof (T3_SND_BD) *
+					 T3_SEND_RCB_ENTRY_COUNT);
+	} else {
+		pDevice->pSendBdVirt = (PT3_SND_BD)
+		    pDevice->pMemView->uIntMem.First32k.BufferDesc;
+		pDevice->SendBdPhy.High = 0;
+		pDevice->SendBdPhy.Low = T3_NIC_SND_BUFFER_DESC_ADDR;
+	}
+
+	/* Allocate memory for packet descriptors. */
+	Size = (pDevice->RxPacketDescCnt +
+		pDevice->TxPacketDescCnt) * MM_PACKET_DESC_SIZE;
+	Status = MM_AllocateMemory (pDevice, Size, (PLM_VOID *) & pPacket);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+	pDevice->pPacketDescBase = (PLM_VOID) pPacket;
+
+	/* Create transmit packet descriptors from the memory block and add them */
+	/* to the TxPacketFreeQ for each send ring. */
+	for (j = 0; j < pDevice->TxPacketDescCnt; j++) {
+		/* Ring index. */
+		pPacket->Flags = 0;
+
+		/* Queue the descriptor in the TxPacketFreeQ of the 'k' ring. */
+		QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
+
+		/* Get the pointer to the next descriptor.  MM_PACKET_DESC_SIZE */
+		/* is the total size of the packet descriptor including the */
+		/* os-specific extensions in the UM_PACKET structure. */
+		pPacket =
+		    (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE);
+	}			/* for(j.. */
+
+	/* Create receive packet descriptors from the memory block and add them */
+	/* to the RxPacketFreeQ.  Create the Standard packet descriptors. */
+	for (j = 0; j < pDevice->RxStdDescCnt; j++) {
+		/* Receive producer ring. */
+		pPacket->u.Rx.RcvProdRing = T3_STD_RCV_PROD_RING;
+
+		/* Receive buffer size. */
+		pPacket->u.Rx.RxBufferSize = MAX_STD_RCV_BUFFER_SIZE;
+
+		/* Add the descriptor to RxPacketFreeQ. */
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+
+		/* Get the pointer to the next descriptor.  MM_PACKET_DESC_SIZE */
+		/* is the total size of the packet descriptor including the */
+		/* os-specific extensions in the UM_PACKET structure. */
+		pPacket =
+		    (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE);
+	}			/* for */
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	/* Create the Jumbo packet descriptors. */
+	for (j = 0; j < pDevice->RxJumboDescCnt; j++) {
+		/* Receive producer ring. */
+		pPacket->u.Rx.RcvProdRing = T3_JUMBO_RCV_PROD_RING;
+
+		/* Receive buffer size. */
+		pPacket->u.Rx.RxBufferSize = pDevice->RxJumboBufferSize;
+
+		/* Add the descriptor to RxPacketFreeQ. */
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+
+		/* Get the pointer to the next descriptor.  MM_PACKET_DESC_SIZE */
+		/* is the total size of the packet descriptor including the */
+		/* os-specific extensions in the UM_PACKET structure. */
+		pPacket =
+		    (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE);
+	}			/* for */
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* Initialize the rest of the packet descriptors. */
+	Status = MM_InitializeUmPackets (pDevice);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+
+	/* if */
+	/* Default receive mask. */
+	pDevice->ReceiveMask = LM_ACCEPT_MULTICAST | LM_ACCEPT_BROADCAST |
+	    LM_ACCEPT_UNICAST;
+
+	/* Make sure we are in the first 32k memory window or NicSendBd. */
+	REG_WR (pDevice, PciCfg.MemWindowBaseAddr, 0);
+
+	/* Initialize the hardware. */
+	Status = LM_ResetAdapter (pDevice);
+	if (Status != LM_STATUS_SUCCESS) {
+		return Status;
+	}
+
+	/* We are done with initialization. */
+	pDevice->InitDone = TRUE;
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_InitializeAdapter */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This function Enables/Disables a given block.                          */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS
+LM_CntrlBlock (PLM_DEVICE_BLOCK pDevice, LM_UINT32 mask, LM_UINT32 cntrl)
+{
+	LM_UINT32 j, i, data;
+	LM_UINT32 MaxWaitCnt;
+
+	MaxWaitCnt = 2;
+	j = 0;
+
+	for (i = 0; i < 32; i++) {
+		if (!(mask & (1 << i)))
+			continue;
+
+		switch (1 << i) {
+		case T3_BLOCK_DMA_RD:
+			data = REG_RD (pDevice, DmaRead.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~DMA_READ_MODE_ENABLE;
+				REG_WR (pDevice, DmaRead.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, DmaRead.Mode) &
+					     DMA_READ_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, DmaRead.Mode,
+					data | DMA_READ_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_DMA_COMP:
+			data = REG_RD (pDevice, DmaComp.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~DMA_COMP_MODE_ENABLE;
+				REG_WR (pDevice, DmaComp.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, DmaComp.Mode) &
+					     DMA_COMP_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, DmaComp.Mode,
+					data | DMA_COMP_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_BD_INITIATOR:
+			data = REG_RD (pDevice, RcvBdIn.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_BD_IN_MODE_ENABLE;
+				REG_WR (pDevice, RcvBdIn.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvBdIn.Mode) &
+					     RCV_BD_IN_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvBdIn.Mode,
+					data | RCV_BD_IN_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_BD_COMP:
+			data = REG_RD (pDevice, RcvBdComp.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_BD_COMP_MODE_ENABLE;
+				REG_WR (pDevice, RcvBdComp.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvBdComp.Mode) &
+					     RCV_BD_COMP_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvBdComp.Mode,
+					data | RCV_BD_COMP_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_DMA_WR:
+			data = REG_RD (pDevice, DmaWrite.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~DMA_WRITE_MODE_ENABLE;
+				REG_WR (pDevice, DmaWrite.Mode, data);
+
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, DmaWrite.Mode) &
+					     DMA_WRITE_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, DmaWrite.Mode,
+					data | DMA_WRITE_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_MSI_HANDLER:
+			data = REG_RD (pDevice, Msi.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~MSI_MODE_ENABLE;
+				REG_WR (pDevice, Msi.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, Msi.Mode) &
+					     MSI_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, Msi.Mode,
+					data | MSI_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_LIST_PLMT:
+			data = REG_RD (pDevice, RcvListPlmt.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_LIST_PLMT_MODE_ENABLE;
+				REG_WR (pDevice, RcvListPlmt.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvListPlmt.Mode)
+					     & RCV_LIST_PLMT_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvListPlmt.Mode,
+					data | RCV_LIST_PLMT_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_LIST_SELECTOR:
+			data = REG_RD (pDevice, RcvListSel.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_LIST_SEL_MODE_ENABLE;
+				REG_WR (pDevice, RcvListSel.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvListSel.Mode) &
+					     RCV_LIST_SEL_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvListSel.Mode,
+					data | RCV_LIST_SEL_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_DATA_INITIATOR:
+			data = REG_RD (pDevice, RcvDataBdIn.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_DATA_BD_IN_MODE_ENABLE;
+				REG_WR (pDevice, RcvDataBdIn.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvDataBdIn.Mode)
+					     & RCV_DATA_BD_IN_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvDataBdIn.Mode,
+					data | RCV_DATA_BD_IN_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_RX_DATA_COMP:
+			data = REG_RD (pDevice, RcvDataComp.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~RCV_DATA_COMP_MODE_ENABLE;
+				REG_WR (pDevice, RcvDataComp.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, RcvDataBdIn.Mode)
+					     & RCV_DATA_COMP_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, RcvDataComp.Mode,
+					data | RCV_DATA_COMP_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_HOST_COALESING:
+			data = REG_RD (pDevice, HostCoalesce.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~HOST_COALESCE_ENABLE;
+				REG_WR (pDevice, HostCoalesce.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndBdIn.Mode) &
+					     HOST_COALESCE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, HostCoalesce.Mode,
+					data | HOST_COALESCE_ENABLE);
+			break;
+
+		case T3_BLOCK_MAC_RX_ENGINE:
+			if (cntrl == LM_DISABLE) {
+				pDevice->RxMode &= ~RX_MODE_ENABLE;
+				REG_WR (pDevice, MacCtrl.RxMode,
+					pDevice->RxMode);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, MacCtrl.RxMode) &
+					     RX_MODE_ENABLE)) {
+						break;
+					}
+					MM_Wait (10);
+				}
+			} else {
+				pDevice->RxMode |= RX_MODE_ENABLE;
+				REG_WR (pDevice, MacCtrl.RxMode,
+					pDevice->RxMode);
+			}
+			break;
+
+		case T3_BLOCK_MBUF_CLUSTER_FREE:
+			data = REG_RD (pDevice, MbufClusterFree.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~MBUF_CLUSTER_FREE_MODE_ENABLE;
+				REG_WR (pDevice, MbufClusterFree.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD
+					     (pDevice,
+					      MbufClusterFree.
+					      Mode) &
+					     MBUF_CLUSTER_FREE_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, MbufClusterFree.Mode,
+					data | MBUF_CLUSTER_FREE_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_SEND_BD_INITIATOR:
+			data = REG_RD (pDevice, SndBdIn.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~SND_BD_IN_MODE_ENABLE;
+				REG_WR (pDevice, SndBdIn.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndBdIn.Mode) &
+					     SND_BD_IN_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, SndBdIn.Mode,
+					data | SND_BD_IN_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_SEND_BD_COMP:
+			data = REG_RD (pDevice, SndBdComp.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~SND_BD_COMP_MODE_ENABLE;
+				REG_WR (pDevice, SndBdComp.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndBdComp.Mode) &
+					     SND_BD_COMP_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, SndBdComp.Mode,
+					data | SND_BD_COMP_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_SEND_BD_SELECTOR:
+			data = REG_RD (pDevice, SndBdSel.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~SND_BD_SEL_MODE_ENABLE;
+				REG_WR (pDevice, SndBdSel.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndBdSel.Mode) &
+					     SND_BD_SEL_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, SndBdSel.Mode,
+					data | SND_BD_SEL_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_SEND_DATA_INITIATOR:
+			data = REG_RD (pDevice, SndDataIn.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~T3_SND_DATA_IN_MODE_ENABLE;
+				REG_WR (pDevice, SndDataIn.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndDataIn.Mode) &
+					     T3_SND_DATA_IN_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, SndDataIn.Mode,
+					data | T3_SND_DATA_IN_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_SEND_DATA_COMP:
+			data = REG_RD (pDevice, SndDataComp.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~SND_DATA_COMP_MODE_ENABLE;
+				REG_WR (pDevice, SndDataComp.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, SndDataComp.Mode)
+					     & SND_DATA_COMP_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, SndDataComp.Mode,
+					data | SND_DATA_COMP_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_MAC_TX_ENGINE:
+			if (cntrl == LM_DISABLE) {
+				pDevice->TxMode &= ~TX_MODE_ENABLE;
+				REG_WR (pDevice, MacCtrl.TxMode,
+					pDevice->TxMode);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, MacCtrl.TxMode) &
+					     TX_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else {
+				pDevice->TxMode |= TX_MODE_ENABLE;
+				REG_WR (pDevice, MacCtrl.TxMode,
+					pDevice->TxMode);
+			}
+			break;
+
+		case T3_BLOCK_MEM_ARBITOR:
+			data = REG_RD (pDevice, MemArbiter.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~T3_MEM_ARBITER_MODE_ENABLE;
+				REG_WR (pDevice, MemArbiter.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, MemArbiter.Mode) &
+					     T3_MEM_ARBITER_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, MemArbiter.Mode,
+					data | T3_MEM_ARBITER_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_MBUF_MANAGER:
+			data = REG_RD (pDevice, BufMgr.Mode);
+			if (cntrl == LM_DISABLE) {
+				data &= ~BUFMGR_MODE_ENABLE;
+				REG_WR (pDevice, BufMgr.Mode, data);
+				for (j = 0; j < MaxWaitCnt; j++) {
+					if (!
+					    (REG_RD (pDevice, BufMgr.Mode) &
+					     BUFMGR_MODE_ENABLE))
+						break;
+					MM_Wait (10);
+				}
+			} else
+				REG_WR (pDevice, BufMgr.Mode,
+					data | BUFMGR_MODE_ENABLE);
+			break;
+
+		case T3_BLOCK_MAC_GLOBAL:
+			if (cntrl == LM_DISABLE) {
+				pDevice->MacMode &= ~(MAC_MODE_ENABLE_TDE |
+						      MAC_MODE_ENABLE_RDE |
+						      MAC_MODE_ENABLE_FHDE);
+			} else {
+				pDevice->MacMode |= (MAC_MODE_ENABLE_TDE |
+						     MAC_MODE_ENABLE_RDE |
+						     MAC_MODE_ENABLE_FHDE);
+			}
+			REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+			break;
+
+		default:
+			return LM_STATUS_FAILURE;
+		}		/* switch */
+
+		if (j >= MaxWaitCnt) {
+			return LM_STATUS_FAILURE;
+		}
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This function reinitializes the adapter.                                */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_ResetAdapter (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+	LM_UINT16 Value16;
+	LM_UINT32 j, k;
+
+	/* Disable interrupt. */
+	LM_DisableInterrupt (pDevice);
+
+	/* May get a spurious interrupt */
+	pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED;
+
+	/* Disable transmit and receive DMA engines.  Abort all pending requests. */
+	if (pDevice->InitDone) {
+		LM_Abort (pDevice);
+	}
+
+	pDevice->ShuttingDown = FALSE;
+
+	LM_ResetChip (pDevice);
+
+	/* Bug: Athlon fix for B3 silicon only.  This bit does not do anything */
+	/* in other chip revisions. */
+	if (pDevice->DelayPciGrant) {
+		Value32 = REG_RD (pDevice, PciCfg.ClockCtrl);
+		REG_WR (pDevice, PciCfg.ClockCtrl, Value32 | BIT_31);
+	}
+
+	if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) {
+		if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) {
+			Value32 = REG_RD (pDevice, PciCfg.PciState);
+			Value32 |= T3_PCI_STATE_RETRY_SAME_DMA;
+			REG_WR (pDevice, PciCfg.PciState, Value32);
+		}
+	}
+
+	/* Enable TaggedStatus mode. */
+	if (pDevice->UseTaggedStatus) {
+		pDevice->MiscHostCtrl |=
+		    MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE;
+	}
+
+	/* Restore PCI configuration registers. */
+	MM_WriteConfig32 (pDevice, PCI_CACHE_LINE_SIZE_REG,
+			  pDevice->SavedCacheLineReg);
+	MM_WriteConfig32 (pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG,
+			  (pDevice->SubsystemId << 16) | pDevice->
+			  SubsystemVendorId);
+
+	/* Clear the statistics block. */
+	for (j = 0x0300; j < 0x0b00; j++) {
+		MEM_WR_OFFSET (pDevice, j, 0);
+	}
+
+	/* Initialize the statistis Block */
+	pDevice->pStatusBlkVirt->Status = 0;
+	pDevice->pStatusBlkVirt->RcvStdConIdx = 0;
+	pDevice->pStatusBlkVirt->RcvJumboConIdx = 0;
+	pDevice->pStatusBlkVirt->RcvMiniConIdx = 0;
+
+	for (j = 0; j < 16; j++) {
+		pDevice->pStatusBlkVirt->Idx[j].RcvProdIdx = 0;
+		pDevice->pStatusBlkVirt->Idx[j].SendConIdx = 0;
+	}
+
+	for (k = 0; k < T3_STD_RCV_RCB_ENTRY_COUNT; k++) {
+		pDevice->pRxStdBdVirt[k].HostAddr.High = 0;
+		pDevice->pRxStdBdVirt[k].HostAddr.Low = 0;
+	}
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	/* Receive jumbo BD buffer. */
+	for (k = 0; k < T3_JUMBO_RCV_RCB_ENTRY_COUNT; k++) {
+		pDevice->pRxJumboBdVirt[k].HostAddr.High = 0;
+		pDevice->pRxJumboBdVirt[k].HostAddr.Low = 0;
+	}
+#endif
+
+	REG_WR (pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl);
+
+	/* GRC mode control register. */
+#ifdef BIG_ENDIAN_PCI		/* Jimmy, this ifdef block deleted in new code! */
+	Value32 =
+	    GRC_MODE_WORD_SWAP_DATA |
+	    GRC_MODE_WORD_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_INT_ON_MAC_ATTN | GRC_MODE_HOST_STACK_UP;
+#else
+	/* No CPU Swap modes for PCI IO */
+	Value32 =
+#ifdef BIG_ENDIAN_HOST
+	    GRC_MODE_BYTE_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_WORD_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_BYTE_SWAP_DATA | GRC_MODE_WORD_SWAP_DATA |
+#else
+	    GRC_MODE_WORD_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_BYTE_SWAP_DATA | GRC_MODE_WORD_SWAP_DATA |
+#endif
+	    GRC_MODE_INT_ON_MAC_ATTN | GRC_MODE_HOST_STACK_UP;
+#endif				/* !BIG_ENDIAN_PCI */
+
+	/* Configure send BD mode. */
+	if (pDevice->NicSendBd == FALSE) {
+		Value32 |= GRC_MODE_HOST_SEND_BDS;
+	} else {
+		Value32 |= GRC_MODE_4X_NIC_BASED_SEND_RINGS;
+	}
+
+	/* Configure pseudo checksum mode. */
+	if (pDevice->NoTxPseudoHdrChksum) {
+		Value32 |= GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM;
+	}
+
+	if (pDevice->NoRxPseudoHdrChksum) {
+		Value32 |= GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM;
+	}
+
+	REG_WR (pDevice, Grc.Mode, Value32);
+
+	/* Setup the timer prescalar register. */
+	REG_WR (pDevice, Grc.MiscCfg, 65 << 1);	/* Clock is alwasy 66Mhz. */
+
+	/* Set up the MBUF pool base address and size. */
+	REG_WR (pDevice, BufMgr.MbufPoolAddr, pDevice->MbufBase);
+	REG_WR (pDevice, BufMgr.MbufPoolSize, pDevice->MbufSize);
+
+	/* Set up the DMA descriptor pool base address and size. */
+	REG_WR (pDevice, BufMgr.DmaDescPoolAddr, T3_NIC_DMA_DESC_POOL_ADDR);
+	REG_WR (pDevice, BufMgr.DmaDescPoolSize, T3_NIC_DMA_DESC_POOL_SIZE);
+
+	/* Configure MBUF and Threshold watermarks */
+	/* Configure the DMA read MBUF low water mark. */
+	if (pDevice->DmaMbufLowMark) {
+		REG_WR (pDevice, BufMgr.MbufReadDmaLowWaterMark,
+			pDevice->DmaMbufLowMark);
+	} else {
+		if (pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) {
+			REG_WR (pDevice, BufMgr.MbufReadDmaLowWaterMark,
+				T3_DEF_DMA_MBUF_LOW_WMARK);
+		} else {
+			REG_WR (pDevice, BufMgr.MbufReadDmaLowWaterMark,
+				T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO);
+		}
+	}
+
+	/* Configure the MAC Rx MBUF low water mark. */
+	if (pDevice->RxMacMbufLowMark) {
+		REG_WR (pDevice, BufMgr.MbufMacRxLowWaterMark,
+			pDevice->RxMacMbufLowMark);
+	} else {
+		if (pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) {
+			REG_WR (pDevice, BufMgr.MbufMacRxLowWaterMark,
+				T3_DEF_RX_MAC_MBUF_LOW_WMARK);
+		} else {
+			REG_WR (pDevice, BufMgr.MbufMacRxLowWaterMark,
+				T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO);
+		}
+	}
+
+	/* Configure the MBUF high water mark. */
+	if (pDevice->MbufHighMark) {
+		REG_WR (pDevice, BufMgr.MbufHighWaterMark,
+			pDevice->MbufHighMark);
+	} else {
+		if (pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) {
+			REG_WR (pDevice, BufMgr.MbufHighWaterMark,
+				T3_DEF_MBUF_HIGH_WMARK);
+		} else {
+			REG_WR (pDevice, BufMgr.MbufHighWaterMark,
+				T3_DEF_MBUF_HIGH_WMARK_JUMBO);
+		}
+	}
+
+	REG_WR (pDevice, BufMgr.DmaLowWaterMark, T3_DEF_DMA_DESC_LOW_WMARK);
+	REG_WR (pDevice, BufMgr.DmaHighWaterMark, T3_DEF_DMA_DESC_HIGH_WMARK);
+
+	/* Enable buffer manager. */
+	REG_WR (pDevice, BufMgr.Mode,
+		BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
+
+	for (j = 0; j < 2000; j++) {
+		if (REG_RD (pDevice, BufMgr.Mode) & BUFMGR_MODE_ENABLE)
+			break;
+		MM_Wait (10);
+	}
+
+	if (j >= 2000) {
+		return LM_STATUS_FAILURE;
+	}
+
+	/* Enable the FTQs. */
+	REG_WR (pDevice, Ftq.Reset, 0xffffffff);
+	REG_WR (pDevice, Ftq.Reset, 0);
+
+	/* Wait until FTQ is ready */
+	for (j = 0; j < 2000; j++) {
+		if (REG_RD (pDevice, Ftq.Reset) == 0)
+			break;
+		MM_Wait (10);
+	}
+
+	if (j >= 2000) {
+		return LM_STATUS_FAILURE;
+	}
+
+	/* Initialize the Standard Receive RCB. */
+	REG_WR (pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.High,
+		pDevice->RxStdBdPhy.High);
+	REG_WR (pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.Low,
+		pDevice->RxStdBdPhy.Low);
+	REG_WR (pDevice, RcvDataBdIn.StdRcvRcb.u.MaxLen_Flags,
+		MAX_STD_RCV_BUFFER_SIZE << 16);
+
+	/* Initialize the Jumbo Receive RCB. */
+	REG_WR (pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags,
+		T3_RCB_FLAG_RING_DISABLED);
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	REG_WR (pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.High,
+		pDevice->RxJumboBdPhy.High);
+	REG_WR (pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.Low,
+		pDevice->RxJumboBdPhy.Low);
+
+	REG_WR (pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags, 0);
+
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* Initialize the Mini Receive RCB. */
+	REG_WR (pDevice, RcvDataBdIn.MiniRcvRcb.u.MaxLen_Flags,
+		T3_RCB_FLAG_RING_DISABLED);
+
+	{
+		REG_WR (pDevice, RcvDataBdIn.StdRcvRcb.NicRingAddr,
+			(LM_UINT32) T3_NIC_STD_RCV_BUFFER_DESC_ADDR);
+		REG_WR (pDevice, RcvDataBdIn.JumboRcvRcb.NicRingAddr,
+			(LM_UINT32) T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR);
+	}
+
+	/* Receive BD Ring replenish threshold. */
+	REG_WR (pDevice, RcvBdIn.StdRcvThreshold, pDevice->RxStdDescCnt / 8);
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	REG_WR (pDevice, RcvBdIn.JumboRcvThreshold,
+		pDevice->RxJumboDescCnt / 8);
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* Disable all the unused rings. */
+	for (j = 0; j < T3_MAX_SEND_RCB_COUNT; j++) {
+		MEM_WR (pDevice, SendRcb[j].u.MaxLen_Flags,
+			T3_RCB_FLAG_RING_DISABLED);
+	}			/* for */
+
+	/* Initialize the indices. */
+	pDevice->SendProdIdx = 0;
+	pDevice->SendConIdx = 0;
+
+	MB_REG_WR (pDevice, Mailbox.SendHostProdIdx[0].Low, 0);
+	MB_REG_WR (pDevice, Mailbox.SendNicProdIdx[0].Low, 0);
+
+	/* Set up host or NIC based send RCB. */
+	if (pDevice->NicSendBd == FALSE) {
+		MEM_WR (pDevice, SendRcb[0].HostRingAddr.High,
+			pDevice->SendBdPhy.High);
+		MEM_WR (pDevice, SendRcb[0].HostRingAddr.Low,
+			pDevice->SendBdPhy.Low);
+
+		/* Set up the NIC ring address in the RCB. */
+		MEM_WR (pDevice, SendRcb[0].NicRingAddr,
+			T3_NIC_SND_BUFFER_DESC_ADDR);
+
+		/* Setup the RCB. */
+		MEM_WR (pDevice, SendRcb[0].u.MaxLen_Flags,
+			T3_SEND_RCB_ENTRY_COUNT << 16);
+
+		for (k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) {
+			pDevice->pSendBdVirt[k].HostAddr.High = 0;
+			pDevice->pSendBdVirt[k].HostAddr.Low = 0;
+		}
+	} else {
+		MEM_WR (pDevice, SendRcb[0].HostRingAddr.High, 0);
+		MEM_WR (pDevice, SendRcb[0].HostRingAddr.Low, 0);
+		MEM_WR (pDevice, SendRcb[0].NicRingAddr,
+			pDevice->SendBdPhy.Low);
+
+		for (k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) {
+			__raw_writel (0,
+				      &(pDevice->pSendBdVirt[k].HostAddr.High));
+			__raw_writel (0,
+				      &(pDevice->pSendBdVirt[k].HostAddr.Low));
+			__raw_writel (0,
+				      &(pDevice->pSendBdVirt[k].u1.Len_Flags));
+			pDevice->ShadowSendBd[k].HostAddr.High = 0;
+			pDevice->ShadowSendBd[k].u1.Len_Flags = 0;
+		}
+	}
+	atomic_set (&pDevice->SendBdLeft, T3_SEND_RCB_ENTRY_COUNT - 1);
+
+	/* Configure the receive return rings. */
+	for (j = 0; j < T3_MAX_RCV_RETURN_RCB_COUNT; j++) {
+		MEM_WR (pDevice, RcvRetRcb[j].u.MaxLen_Flags,
+			T3_RCB_FLAG_RING_DISABLED);
+	}
+
+	pDevice->RcvRetConIdx = 0;
+
+	MEM_WR (pDevice, RcvRetRcb[0].HostRingAddr.High,
+		pDevice->RcvRetBdPhy.High);
+	MEM_WR (pDevice, RcvRetRcb[0].HostRingAddr.Low,
+		pDevice->RcvRetBdPhy.Low);
+
+	/* Set up the NIC ring address in the RCB. */
+	/* Not very clear from the spec.  I am guessing that for Receive */
+	/* Return Ring, NicRingAddr is not used. */
+	MEM_WR (pDevice, RcvRetRcb[0].NicRingAddr, 0);
+
+	/* Setup the RCB. */
+	MEM_WR (pDevice, RcvRetRcb[0].u.MaxLen_Flags,
+		T3_RCV_RETURN_RCB_ENTRY_COUNT << 16);
+
+	/* Reinitialize RX ring producer index */
+	MB_REG_WR (pDevice, Mailbox.RcvStdProdIdx.Low, 0);
+	MB_REG_WR (pDevice, Mailbox.RcvJumboProdIdx.Low, 0);
+	MB_REG_WR (pDevice, Mailbox.RcvMiniProdIdx.Low, 0);
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	pDevice->RxJumboProdIdx = 0;
+	pDevice->RxJumboQueuedCnt = 0;
+#endif
+
+	/* Reinitialize our copy of the indices. */
+	pDevice->RxStdProdIdx = 0;
+	pDevice->RxStdQueuedCnt = 0;
+
+#if T3_JUMBO_RCV_ENTRY_COUNT
+	pDevice->RxJumboProdIdx = 0;
+#endif				/* T3_JUMBO_RCV_ENTRY_COUNT */
+
+	/* Configure the MAC address. */
+	LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+
+	/* Initialize the transmit random backoff seed. */
+	Value32 = (pDevice->NodeAddress[0] + pDevice->NodeAddress[1] +
+		   pDevice->NodeAddress[2] + pDevice->NodeAddress[3] +
+		   pDevice->NodeAddress[4] + pDevice->NodeAddress[5]) &
+	    MAC_TX_BACKOFF_SEED_MASK;
+	REG_WR (pDevice, MacCtrl.TxBackoffSeed, Value32);
+
+	/* Receive MTU.  Frames larger than the MTU is marked as oversized. */
+	REG_WR (pDevice, MacCtrl.MtuSize, pDevice->RxMtu + 8);	/* CRC + VLAN. */
+
+	/* Configure Time slot/IPG per 802.3 */
+	REG_WR (pDevice, MacCtrl.TxLengths, 0x2620);
+
+	/*
+	 * Configure Receive Rules so that packets don't match
+	 * Programmble rule will be queued to Return Ring 1
+	 */
+	REG_WR (pDevice, MacCtrl.RcvRuleCfg, RX_RULE_DEFAULT_CLASS);
+
+	/*
+	 * Configure to have 16 Classes of Services (COS) and one
+	 * queue per class.  Bad frames are queued to RRR#1.
+	 * And frames don't match rules are also queued to COS#1.
+	 */
+	REG_WR (pDevice, RcvListPlmt.Config, 0x181);
+
+	/* Enable Receive Placement Statistics */
+	REG_WR (pDevice, RcvListPlmt.StatsEnableMask, 0xffffff);
+	REG_WR (pDevice, RcvListPlmt.StatsCtrl, RCV_LIST_STATS_ENABLE);
+
+	/* Enable Send Data Initator Statistics */
+	REG_WR (pDevice, SndDataIn.StatsEnableMask, 0xffffff);
+	REG_WR (pDevice, SndDataIn.StatsCtrl,
+		T3_SND_DATA_IN_STATS_CTRL_ENABLE |
+		T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE);
+
+	/* Disable the host coalescing state machine before configuring it's */
+	/* parameters. */
+	REG_WR (pDevice, HostCoalesce.Mode, 0);
+	for (j = 0; j < 2000; j++) {
+		Value32 = REG_RD (pDevice, HostCoalesce.Mode);
+		if (!(Value32 & HOST_COALESCE_ENABLE)) {
+			break;
+		}
+		MM_Wait (10);
+	}
+
+	/* Host coalescing configurations. */
+	REG_WR (pDevice, HostCoalesce.RxCoalescingTicks,
+		pDevice->RxCoalescingTicks);
+	REG_WR (pDevice, HostCoalesce.TxCoalescingTicks,
+		pDevice->TxCoalescingTicks);
+	REG_WR (pDevice, HostCoalesce.RxMaxCoalescedFrames,
+		pDevice->RxMaxCoalescedFrames);
+	REG_WR (pDevice, HostCoalesce.TxMaxCoalescedFrames,
+		pDevice->TxMaxCoalescedFrames);
+	REG_WR (pDevice, HostCoalesce.RxCoalescedTickDuringInt,
+		pDevice->RxCoalescingTicksDuringInt);
+	REG_WR (pDevice, HostCoalesce.TxCoalescedTickDuringInt,
+		pDevice->TxCoalescingTicksDuringInt);
+	REG_WR (pDevice, HostCoalesce.RxMaxCoalescedFramesDuringInt,
+		pDevice->RxMaxCoalescedFramesDuringInt);
+	REG_WR (pDevice, HostCoalesce.TxMaxCoalescedFramesDuringInt,
+		pDevice->TxMaxCoalescedFramesDuringInt);
+
+	/* Initialize the address of the status block.  The NIC will DMA */
+	/* the status block to this memory which resides on the host. */
+	REG_WR (pDevice, HostCoalesce.StatusBlkHostAddr.High,
+		pDevice->StatusBlkPhy.High);
+	REG_WR (pDevice, HostCoalesce.StatusBlkHostAddr.Low,
+		pDevice->StatusBlkPhy.Low);
+
+	/* Initialize the address of the statistics block.  The NIC will DMA */
+	/* the statistics to this block of memory. */
+	REG_WR (pDevice, HostCoalesce.StatsBlkHostAddr.High,
+		pDevice->StatsBlkPhy.High);
+	REG_WR (pDevice, HostCoalesce.StatsBlkHostAddr.Low,
+		pDevice->StatsBlkPhy.Low);
+
+	REG_WR (pDevice, HostCoalesce.StatsCoalescingTicks,
+		pDevice->StatsCoalescingTicks);
+
+	REG_WR (pDevice, HostCoalesce.StatsBlkNicAddr, 0x300);
+	REG_WR (pDevice, HostCoalesce.StatusBlkNicAddr, 0xb00);
+
+	/* Enable Host Coalesing state machine */
+	REG_WR (pDevice, HostCoalesce.Mode, HOST_COALESCE_ENABLE |
+		pDevice->CoalesceMode);
+
+	/* Enable the Receive BD Completion state machine. */
+	REG_WR (pDevice, RcvBdComp.Mode, RCV_BD_COMP_MODE_ENABLE |
+		RCV_BD_COMP_MODE_ATTN_ENABLE);
+
+	/* Enable the Receive List Placement state machine. */
+	REG_WR (pDevice, RcvListPlmt.Mode, RCV_LIST_PLMT_MODE_ENABLE);
+
+	/* Enable the Receive List Selector state machine. */
+	REG_WR (pDevice, RcvListSel.Mode, RCV_LIST_SEL_MODE_ENABLE |
+		RCV_LIST_SEL_MODE_ATTN_ENABLE);
+
+	/* Enable transmit DMA, clear statistics. */
+	pDevice->MacMode = MAC_MODE_ENABLE_TX_STATISTICS |
+	    MAC_MODE_ENABLE_RX_STATISTICS | MAC_MODE_ENABLE_TDE |
+	    MAC_MODE_ENABLE_RDE | MAC_MODE_ENABLE_FHDE;
+	REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode |
+		MAC_MODE_CLEAR_RX_STATISTICS | MAC_MODE_CLEAR_TX_STATISTICS);
+
+	/* GRC miscellaneous local control register. */
+	pDevice->GrcLocalCtrl = GRC_MISC_LOCAL_CTRL_INT_ON_ATTN |
+	    GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM;
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		pDevice->GrcLocalCtrl |= GRC_MISC_LOCAL_CTRL_GPIO_OE1 |
+		    GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1;
+	}
+
+	REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl);
+	MM_Wait (40);
+
+	/* Reset RX counters. */
+	for (j = 0; j < sizeof (LM_RX_COUNTERS); j++) {
+		((PLM_UINT8) & pDevice->RxCounters)[j] = 0;
+	}
+
+	/* Reset TX counters. */
+	for (j = 0; j < sizeof (LM_TX_COUNTERS); j++) {
+		((PLM_UINT8) & pDevice->TxCounters)[j] = 0;
+	}
+
+	MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 0);
+
+	/* Enable the DMA Completion state machine. */
+	REG_WR (pDevice, DmaComp.Mode, DMA_COMP_MODE_ENABLE);
+
+	/* Enable the DMA Write state machine. */
+	Value32 = DMA_WRITE_MODE_ENABLE |
+	    DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE |
+	    DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE |
+	    DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE |
+	    DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE |
+	    DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE |
+	    DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE |
+	    DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE |
+	    DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE;
+	REG_WR (pDevice, DmaWrite.Mode, Value32);
+
+	if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) {
+		if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) {
+			Value16 = REG_RD (pDevice, PciCfg.PciXCommand);
+			Value16 &=
+			    ~(PCIX_CMD_MAX_SPLIT_MASK |
+			      PCIX_CMD_MAX_BURST_MASK);
+			Value16 |=
+			    ((PCIX_CMD_MAX_BURST_CPIOB <<
+			      PCIX_CMD_MAX_BURST_SHL) &
+			     PCIX_CMD_MAX_BURST_MASK);
+			if (pDevice->SplitModeEnable == SPLIT_MODE_ENABLE) {
+				Value16 |=
+				    (pDevice->
+				     SplitModeMaxReq << PCIX_CMD_MAX_SPLIT_SHL)
+				    & PCIX_CMD_MAX_SPLIT_MASK;
+			}
+			REG_WR (pDevice, PciCfg.PciXCommand, Value16);
+		}
+	}
+
+	/* Enable the Read DMA state machine. */
+	Value32 = DMA_READ_MODE_ENABLE |
+	    DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE |
+	    DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE |
+	    DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE |
+	    DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE |
+	    DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE |
+	    DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE |
+	    DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE |
+	    DMA_READ_MODE_LONG_READ_ATTN_ENABLE;
+
+	if (pDevice->SplitModeEnable == SPLIT_MODE_ENABLE) {
+		Value32 |= DMA_READ_MODE_SPLIT_ENABLE;
+	}
+	REG_WR (pDevice, DmaRead.Mode, Value32);
+
+	/* Enable the Receive Data Completion state machine. */
+	REG_WR (pDevice, RcvDataComp.Mode, RCV_DATA_COMP_MODE_ENABLE |
+		RCV_DATA_COMP_MODE_ATTN_ENABLE);
+
+	/* Enable the Mbuf Cluster Free state machine. */
+	REG_WR (pDevice, MbufClusterFree.Mode, MBUF_CLUSTER_FREE_MODE_ENABLE);
+
+	/* Enable the Send Data Completion state machine. */
+	REG_WR (pDevice, SndDataComp.Mode, SND_DATA_COMP_MODE_ENABLE);
+
+	/* Enable the Send BD Completion state machine. */
+	REG_WR (pDevice, SndBdComp.Mode, SND_BD_COMP_MODE_ENABLE |
+		SND_BD_COMP_MODE_ATTN_ENABLE);
+
+	/* Enable the Receive BD Initiator state machine. */
+	REG_WR (pDevice, RcvBdIn.Mode, RCV_BD_IN_MODE_ENABLE |
+		RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE);
+
+	/* Enable the Receive Data and Receive BD Initiator state machine. */
+	REG_WR (pDevice, RcvDataBdIn.Mode, RCV_DATA_BD_IN_MODE_ENABLE |
+		RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE);
+
+	/* Enable the Send Data Initiator state machine. */
+	REG_WR (pDevice, SndDataIn.Mode, T3_SND_DATA_IN_MODE_ENABLE);
+
+	/* Enable the Send BD Initiator state machine. */
+	REG_WR (pDevice, SndBdIn.Mode, SND_BD_IN_MODE_ENABLE |
+		SND_BD_IN_MODE_ATTN_ENABLE);
+
+	/* Enable the Send BD Selector state machine. */
+	REG_WR (pDevice, SndBdSel.Mode, SND_BD_SEL_MODE_ENABLE |
+		SND_BD_SEL_MODE_ATTN_ENABLE);
+
+#if INCLUDE_5701_AX_FIX
+	/* Load the firmware for the 5701_A0 workaround. */
+	if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0) {
+		LM_LoadRlsFirmware (pDevice);
+	}
+#endif
+
+	/* Enable the transmitter. */
+	pDevice->TxMode = TX_MODE_ENABLE;
+	REG_WR (pDevice, MacCtrl.TxMode, pDevice->TxMode);
+
+	/* Enable the receiver. */
+	pDevice->RxMode = RX_MODE_ENABLE;
+	REG_WR (pDevice, MacCtrl.RxMode, pDevice->RxMode);
+
+	if (pDevice->RestoreOnWakeUp) {
+		pDevice->RestoreOnWakeUp = FALSE;
+		pDevice->DisableAutoNeg = pDevice->WakeUpDisableAutoNeg;
+		pDevice->RequestedMediaType = pDevice->WakeUpRequestedMediaType;
+	}
+
+	/* Disable auto polling. */
+	pDevice->MiMode = 0xc0000;
+	REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+	    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+		Value32 = LED_CTRL_PHY_MODE_1;
+	} else {
+		if (pDevice->LedMode == LED_MODE_OUTPUT) {
+			Value32 = LED_CTRL_PHY_MODE_2;
+		} else {
+			Value32 = LED_CTRL_PHY_MODE_1;
+		}
+	}
+	REG_WR (pDevice, MacCtrl.LedCtrl, Value32);
+
+	/* Activate Link to enable MAC state machine */
+	REG_WR (pDevice, MacCtrl.MiStatus, MI_STATUS_ENABLE_LINK_STATUS_ATTN);
+
+	if (pDevice->EnableTbi) {
+		REG_WR (pDevice, MacCtrl.RxMode, RX_MODE_RESET);
+		MM_Wait (10);
+		REG_WR (pDevice, MacCtrl.RxMode, pDevice->RxMode);
+		if (pDevice->ChipRevId == T3_CHIP_ID_5703_A1) {
+			REG_WR (pDevice, MacCtrl.SerdesCfg, 0x616000);
+		}
+	}
+	/* Setup the phy chip. */
+	LM_SetupPhy (pDevice);
+
+	if (!pDevice->EnableTbi) {
+		/* Clear CRC stats */
+		LM_ReadPhy (pDevice, 0x1e, &Value32);
+		LM_WritePhy (pDevice, 0x1e, Value32 | 0x8000);
+		LM_ReadPhy (pDevice, 0x14, &Value32);
+	}
+
+	/* Set up the receive mask. */
+	LM_SetReceiveMask (pDevice, pDevice->ReceiveMask);
+
+	/* Queue Rx packet buffers. */
+	if (pDevice->QueueRxPackets) {
+		LM_QueueRxPackets (pDevice);
+	}
+
+	/* Enable interrupt to the host. */
+	if (pDevice->InitDone) {
+		LM_EnableInterrupt (pDevice);
+	}
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_ResetAdapter */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine disables the adapter from generating interrupts.           */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_DisableInterrupt (PLM_DEVICE_BLOCK pDevice)
+{
+	REG_WR (pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl |
+		MISC_HOST_CTRL_MASK_PCI_INT);
+	MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 1);
+
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine enables the adapter to generate interrupts.                */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_EnableInterrupt (PLM_DEVICE_BLOCK pDevice)
+{
+	REG_WR (pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl &
+		~MISC_HOST_CTRL_MASK_PCI_INT);
+	MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 0);
+
+	if (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
+		REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl |
+			GRC_MISC_LOCAL_CTRL_SET_INT);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine puts a packet on the wire if there is a transmit DMA       */
+/*    descriptor available; otherwise the packet is queued for later          */
+/*    transmission.  If the second argue is NULL, this routine will put       */
+/*    the queued packet on the wire if possible.                              */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+#if 0
+LM_STATUS LM_SendPacket (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+	LM_UINT32 FragCount;
+	PT3_SND_BD pSendBd;
+	PT3_SND_BD pShadowSendBd;
+	LM_UINT32 Value32, Len;
+	LM_UINT32 Idx;
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		return LM_5700SendPacket (pDevice, pPacket);
+	}
+
+	/* Update the SendBdLeft count. */
+	atomic_sub (pPacket->u.Tx.FragCount, &pDevice->SendBdLeft);
+
+	/* Initalize the send buffer descriptors. */
+	Idx = pDevice->SendProdIdx;
+
+	pSendBd = &pDevice->pSendBdVirt[Idx];
+
+	/* Next producer index. */
+	if (pDevice->NicSendBd == TRUE) {
+		T3_64BIT_HOST_ADDR paddr;
+
+		pShadowSendBd = &pDevice->ShadowSendBd[Idx];
+		for (FragCount = 0;;) {
+			MM_MapTxDma (pDevice, pPacket, &paddr, &Len, FragCount);
+			/* Initialize the pointer to the send buffer fragment. */
+			if (paddr.High != pShadowSendBd->HostAddr.High) {
+				__raw_writel (paddr.High,
+					      &(pSendBd->HostAddr.High));
+				pShadowSendBd->HostAddr.High = paddr.High;
+			}
+			__raw_writel (paddr.Low, &(pSendBd->HostAddr.Low));
+
+			/* Setup the control flags and send buffer size. */
+			Value32 = (Len << 16) | pPacket->Flags;
+
+			Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK;
+
+			FragCount++;
+			if (FragCount >= pPacket->u.Tx.FragCount) {
+				Value32 |= SND_BD_FLAG_END;
+				if (Value32 != pShadowSendBd->u1.Len_Flags) {
+					__raw_writel (Value32,
+						      &(pSendBd->u1.Len_Flags));
+					pShadowSendBd->u1.Len_Flags = Value32;
+				}
+				if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) {
+					__raw_writel (pPacket->VlanTag,
+						      &(pSendBd->u2.VlanTag));
+				}
+				break;
+			} else {
+				if (Value32 != pShadowSendBd->u1.Len_Flags) {
+					__raw_writel (Value32,
+						      &(pSendBd->u1.Len_Flags));
+					pShadowSendBd->u1.Len_Flags = Value32;
+				}
+				if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) {
+					__raw_writel (pPacket->VlanTag,
+						      &(pSendBd->u2.VlanTag));
+				}
+			}
+
+			pSendBd++;
+			pShadowSendBd++;
+			if (Idx == 0) {
+				pSendBd = &pDevice->pSendBdVirt[0];
+				pShadowSendBd = &pDevice->ShadowSendBd[0];
+			}
+		}		/* for */
+
+		/* Put the packet descriptor in the ActiveQ. */
+		QQ_PushTail (&pDevice->TxPacketActiveQ.Container, pPacket);
+
+		wmb ();
+		MB_REG_WR (pDevice, Mailbox.SendNicProdIdx[0].Low, Idx);
+
+	} else {
+		for (FragCount = 0;;) {
+			/* Initialize the pointer to the send buffer fragment. */
+			MM_MapTxDma (pDevice, pPacket, &pSendBd->HostAddr, &Len,
+				     FragCount);
+
+			pSendBd->u2.VlanTag = pPacket->VlanTag;
+
+			/* Setup the control flags and send buffer size. */
+			Value32 = (Len << 16) | pPacket->Flags;
+
+			Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK;
+
+			FragCount++;
+			if (FragCount >= pPacket->u.Tx.FragCount) {
+				pSendBd->u1.Len_Flags =
+				    Value32 | SND_BD_FLAG_END;
+				break;
+			} else {
+				pSendBd->u1.Len_Flags = Value32;
+			}
+			pSendBd++;
+			if (Idx == 0) {
+				pSendBd = &pDevice->pSendBdVirt[0];
+			}
+		}		/* for */
+
+		/* Put the packet descriptor in the ActiveQ. */
+		QQ_PushTail (&pDevice->TxPacketActiveQ.Container, pPacket);
+
+		wmb ();
+		MB_REG_WR (pDevice, Mailbox.SendHostProdIdx[0].Low, Idx);
+
+	}
+
+	/* Update the producer index. */
+	pDevice->SendProdIdx = Idx;
+
+	return LM_STATUS_SUCCESS;
+}
+#endif
+
+LM_STATUS LM_SendPacket (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
+{
+	LM_UINT32 FragCount;
+	PT3_SND_BD pSendBd, pTmpSendBd, pShadowSendBd;
+	T3_SND_BD NicSendBdArr[MAX_FRAGMENT_COUNT];
+	LM_UINT32 StartIdx, Idx;
+
+	while (1) {
+		/* Initalize the send buffer descriptors. */
+		StartIdx = Idx = pDevice->SendProdIdx;
+
+		if (pDevice->NicSendBd) {
+			pTmpSendBd = pSendBd = &NicSendBdArr[0];
+		} else {
+			pTmpSendBd = pSendBd = &pDevice->pSendBdVirt[Idx];
+		}
+
+		/* Next producer index. */
+		for (FragCount = 0;;) {
+			LM_UINT32 Value32, Len;
+
+			/* Initialize the pointer to the send buffer fragment. */
+			MM_MapTxDma (pDevice, pPacket, &pSendBd->HostAddr, &Len,
+				     FragCount);
+
+			pSendBd->u2.VlanTag = pPacket->VlanTag;
+
+			/* Setup the control flags and send buffer size. */
+			Value32 = (Len << 16) | pPacket->Flags;
+
+			Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK;
+
+			FragCount++;
+			if (FragCount >= pPacket->u.Tx.FragCount) {
+				pSendBd->u1.Len_Flags =
+				    Value32 | SND_BD_FLAG_END;
+				break;
+			} else {
+				pSendBd->u1.Len_Flags = Value32;
+			}
+			pSendBd++;
+			if ((Idx == 0) && !pDevice->NicSendBd) {
+				pSendBd = &pDevice->pSendBdVirt[0];
+			}
+		}		/* for */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+			if (LM_Test4GBoundary (pDevice, pPacket, pTmpSendBd) ==
+			    LM_STATUS_SUCCESS) {
+				if (MM_CoalesceTxBuffer (pDevice, pPacket) !=
+				    LM_STATUS_SUCCESS) {
+					QQ_PushHead (&pDevice->TxPacketFreeQ.
+						     Container, pPacket);
+					return LM_STATUS_FAILURE;
+				}
+				continue;
+			}
+		}
+		break;
+	}
+	/* Put the packet descriptor in the ActiveQ. */
+	QQ_PushTail (&pDevice->TxPacketActiveQ.Container, pPacket);
+
+	if (pDevice->NicSendBd) {
+		pSendBd = &pDevice->pSendBdVirt[StartIdx];
+		pShadowSendBd = &pDevice->ShadowSendBd[StartIdx];
+
+		while (StartIdx != Idx) {
+			LM_UINT32 Value32;
+
+			if ((Value32 = pTmpSendBd->HostAddr.High) !=
+			    pShadowSendBd->HostAddr.High) {
+				__raw_writel (Value32,
+					      &(pSendBd->HostAddr.High));
+				pShadowSendBd->HostAddr.High = Value32;
+			}
+
+			__raw_writel (pTmpSendBd->HostAddr.Low,
+				      &(pSendBd->HostAddr.Low));
+
+			if ((Value32 = pTmpSendBd->u1.Len_Flags) !=
+			    pShadowSendBd->u1.Len_Flags) {
+				__raw_writel (Value32,
+					      &(pSendBd->u1.Len_Flags));
+				pShadowSendBd->u1.Len_Flags = Value32;
+			}
+
+			if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) {
+				__raw_writel (pTmpSendBd->u2.VlanTag,
+					      &(pSendBd->u2.VlanTag));
+			}
+
+			StartIdx =
+			    (StartIdx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK;
+			if (StartIdx == 0)
+				pSendBd = &pDevice->pSendBdVirt[0];
+			else
+				pSendBd++;
+			pTmpSendBd++;
+		}
+		wmb ();
+		MB_REG_WR (pDevice, Mailbox.SendNicProdIdx[0].Low, Idx);
+
+		if (T3_CHIP_REV (pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) {
+			MB_REG_WR (pDevice, Mailbox.SendNicProdIdx[0].Low, Idx);
+		}
+	} else {
+		wmb ();
+		MB_REG_WR (pDevice, Mailbox.SendHostProdIdx[0].Low, Idx);
+
+		if (T3_CHIP_REV (pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) {
+			MB_REG_WR (pDevice, Mailbox.SendHostProdIdx[0].Low,
+				   Idx);
+		}
+	}
+
+	/* Update the SendBdLeft count. */
+	atomic_sub (pPacket->u.Tx.FragCount, &pDevice->SendBdLeft);
+
+	/* Update the producer index. */
+	pDevice->SendProdIdx = Idx;
+
+	return LM_STATUS_SUCCESS;
+}
+
+STATIC LM_STATUS
+LM_Test4GBoundary (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket,
+		   PT3_SND_BD pSendBd)
+{
+	int FragCount;
+	LM_UINT32 Idx, Base, Len;
+
+	Idx = pDevice->SendProdIdx;
+	for (FragCount = 0;;) {
+		Len = pSendBd->u1.Len_Flags >> 16;
+		if (((Base = pSendBd->HostAddr.Low) > 0xffffdcc0) &&
+		    (pSendBd->HostAddr.High == 0) &&
+		    ((Base + 8 + Len) < Base)) {
+			return LM_STATUS_SUCCESS;
+		}
+		FragCount++;
+		if (FragCount >= pPacket->u.Tx.FragCount) {
+			break;
+		}
+		pSendBd++;
+		if (!pDevice->NicSendBd) {
+			Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK;
+			if (Idx == 0) {
+				pSendBd = &pDevice->pSendBdVirt[0];
+			}
+		}
+	}
+	return LM_STATUS_FAILURE;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+__inline static unsigned long
+ComputeCrc32 (unsigned char *pBuffer, unsigned long BufferSize)
+{
+	unsigned long Reg;
+	unsigned long Tmp;
+	unsigned long j, k;
+
+	Reg = 0xffffffff;
+
+	for (j = 0; j < BufferSize; j++) {
+		Reg ^= pBuffer[j];
+
+		for (k = 0; k < 8; k++) {
+			Tmp = Reg & 0x01;
+
+			Reg >>= 1;
+
+			if (Tmp) {
+				Reg ^= 0xedb88320;
+			}
+		}
+	}
+
+	return ~Reg;
+}				/* ComputeCrc32 */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This routine sets the receive control register according to ReceiveMask */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_SetReceiveMask (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Mask)
+{
+	LM_UINT32 ReceiveMask;
+	LM_UINT32 RxMode;
+	LM_UINT32 j, k;
+
+	ReceiveMask = Mask;
+
+	RxMode = pDevice->RxMode;
+
+	if (Mask & LM_ACCEPT_UNICAST) {
+		Mask &= ~LM_ACCEPT_UNICAST;
+	}
+
+	if (Mask & LM_ACCEPT_MULTICAST) {
+		Mask &= ~LM_ACCEPT_MULTICAST;
+	}
+
+	if (Mask & LM_ACCEPT_ALL_MULTICAST) {
+		Mask &= ~LM_ACCEPT_ALL_MULTICAST;
+	}
+
+	if (Mask & LM_ACCEPT_BROADCAST) {
+		Mask &= ~LM_ACCEPT_BROADCAST;
+	}
+
+	RxMode &= ~RX_MODE_PROMISCUOUS_MODE;
+	if (Mask & LM_PROMISCUOUS_MODE) {
+		RxMode |= RX_MODE_PROMISCUOUS_MODE;
+		Mask &= ~LM_PROMISCUOUS_MODE;
+	}
+
+	RxMode &= ~(RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED);
+	if (Mask & LM_ACCEPT_ERROR_PACKET) {
+		RxMode |= RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED;
+		Mask &= ~LM_ACCEPT_ERROR_PACKET;
+	}
+
+	/* Make sure all the bits are valid before committing changes. */
+	if (Mask) {
+		return LM_STATUS_FAILURE;
+	}
+
+	/* Commit the new filter. */
+	pDevice->RxMode = RxMode;
+	REG_WR (pDevice, MacCtrl.RxMode, RxMode);
+
+	pDevice->ReceiveMask = ReceiveMask;
+
+	/* Set up the MC hash table. */
+	if (ReceiveMask & LM_ACCEPT_ALL_MULTICAST) {
+		for (k = 0; k < 4; k++) {
+			REG_WR (pDevice, MacCtrl.HashReg[k], 0xffffffff);
+		}
+	} else if (ReceiveMask & LM_ACCEPT_MULTICAST) {
+		LM_UINT32 HashReg[4];
+
+		HashReg[0] = 0;
+		HashReg[1] = 0;
+		HashReg[2] = 0;
+		HashReg[3] = 0;
+		for (j = 0; j < pDevice->McEntryCount; j++) {
+			LM_UINT32 RegIndex;
+			LM_UINT32 Bitpos;
+			LM_UINT32 Crc32;
+
+			Crc32 =
+			    ComputeCrc32 (pDevice->McTable[j],
+					  ETHERNET_ADDRESS_SIZE);
+
+			/* The most significant 7 bits of the CRC32 (no inversion), */
+			/* are used to index into one of the possible 128 bit positions. */
+			Bitpos = ~Crc32 & 0x7f;
+
+			/* Hash register index. */
+			RegIndex = (Bitpos & 0x60) >> 5;
+
+			/* Bit to turn on within a hash register. */
+			Bitpos &= 0x1f;
+
+			/* Enable the multicast bit. */
+			HashReg[RegIndex] |= (1 << Bitpos);
+		}
+
+		/* REV_AX has problem with multicast filtering where it uses both */
+		/* DA and SA to perform hashing. */
+		for (k = 0; k < 4; k++) {
+			REG_WR (pDevice, MacCtrl.HashReg[k], HashReg[k]);
+		}
+	} else {
+		/* Reject all multicast frames. */
+		for (j = 0; j < 4; j++) {
+			REG_WR (pDevice, MacCtrl.HashReg[j], 0);
+		}
+	}
+
+	/* By default, Tigon3 will accept broadcast frames.  We need to setup */
+	if (ReceiveMask & LM_ACCEPT_BROADCAST) {
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule,
+			REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value,
+			REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule,
+			REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value,
+			REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK);
+	} else {
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule,
+			REJECT_BROADCAST_RULE1_RULE);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value,
+			REJECT_BROADCAST_RULE1_VALUE);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule,
+			REJECT_BROADCAST_RULE2_RULE);
+		REG_WR (pDevice,
+			MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value,
+			REJECT_BROADCAST_RULE2_VALUE);
+	}
+
+	/* disable the rest of the rules. */
+	for (j = RCV_LAST_RULE_IDX; j < 16; j++) {
+		REG_WR (pDevice, MacCtrl.RcvRules[j].Rule, 0);
+		REG_WR (pDevice, MacCtrl.RcvRules[j].Value, 0);
+	}
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_SetReceiveMask */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    Disable the interrupt and put the transmitter and receiver engines in   */
+/*    an idle state.  Also aborts all pending send requests and receive       */
+/*    buffers.                                                                */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_Abort (PLM_DEVICE_BLOCK pDevice)
+{
+	PLM_PACKET pPacket;
+	LM_UINT Idx;
+
+	LM_DisableInterrupt (pDevice);
+
+	/* Disable all the state machines. */
+	LM_CntrlBlock (pDevice, T3_BLOCK_MAC_RX_ENGINE, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_BD_INITIATOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_LIST_PLMT, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_LIST_SELECTOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_DATA_INITIATOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_DATA_COMP, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_RX_BD_COMP, LM_DISABLE);
+
+	LM_CntrlBlock (pDevice, T3_BLOCK_SEND_BD_SELECTOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_SEND_BD_INITIATOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_SEND_DATA_INITIATOR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_DMA_RD, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_SEND_DATA_COMP, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_DMA_COMP, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_SEND_BD_COMP, LM_DISABLE);
+
+	/* Clear TDE bit */
+	pDevice->MacMode &= ~MAC_MODE_ENABLE_TDE;
+	REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+
+	LM_CntrlBlock (pDevice, T3_BLOCK_MAC_TX_ENGINE, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_HOST_COALESING, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_DMA_WR, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_MBUF_CLUSTER_FREE, LM_DISABLE);
+
+	/* Reset all FTQs */
+	REG_WR (pDevice, Ftq.Reset, 0xffffffff);
+	REG_WR (pDevice, Ftq.Reset, 0x0);
+
+	LM_CntrlBlock (pDevice, T3_BLOCK_MBUF_MANAGER, LM_DISABLE);
+	LM_CntrlBlock (pDevice, T3_BLOCK_MEM_ARBITOR, LM_DISABLE);
+
+	MM_ACQUIRE_INT_LOCK (pDevice);
+
+	/* Abort packets that have already queued to go out. */
+	pPacket = (PLM_PACKET) QQ_PopHead (&pDevice->TxPacketActiveQ.Container);
+	while (pPacket) {
+
+		pPacket->PacketStatus = LM_STATUS_TRANSMIT_ABORTED;
+		pDevice->TxCounters.TxPacketAbortedCnt++;
+
+		atomic_add (pPacket->u.Tx.FragCount, &pDevice->SendBdLeft);
+
+		QQ_PushTail (&pDevice->TxPacketXmittedQ.Container, pPacket);
+
+		pPacket = (PLM_PACKET)
+		    QQ_PopHead (&pDevice->TxPacketActiveQ.Container);
+	}
+
+	/* Cleanup the receive return rings. */
+	LM_ServiceRxInterrupt (pDevice);
+
+	/* Don't want to indicate rx packets in Ndis miniport shutdown context. */
+	/* Doing so may cause system crash. */
+	if (!pDevice->ShuttingDown) {
+		/* Indicate packets to the protocol. */
+		MM_IndicateTxPackets (pDevice);
+
+		/* Indicate received packets to the protocols. */
+		MM_IndicateRxPackets (pDevice);
+	} else {
+		/* Move the receive packet descriptors in the ReceivedQ to the */
+		/* free queue. */
+		for (;;) {
+			pPacket =
+			    (PLM_PACKET) QQ_PopHead (&pDevice->
+						     RxPacketReceivedQ.
+						     Container);
+			if (pPacket == NULL) {
+				break;
+			}
+			QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
+				     pPacket);
+		}
+	}
+
+	/* Clean up the Std Receive Producer ring. */
+	Idx = pDevice->pStatusBlkVirt->RcvStdConIdx;
+
+	while (Idx != pDevice->RxStdProdIdx) {
+		pPacket = (PLM_PACKET) (MM_UINT_PTR (pDevice->pPacketDescBase) +
+					MM_UINT_PTR (pDevice->pRxStdBdVirt[Idx].
+						     Opaque));
+
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+
+		Idx = (Idx + 1) & T3_STD_RCV_RCB_ENTRY_COUNT_MASK;
+	}			/* while */
+
+	/* Reinitialize our copy of the indices. */
+	pDevice->RxStdProdIdx = 0;
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	/* Clean up the Jumbo Receive Producer ring. */
+	Idx = pDevice->pStatusBlkVirt->RcvJumboConIdx;
+
+	while (Idx != pDevice->RxJumboProdIdx) {
+		pPacket = (PLM_PACKET) (MM_UINT_PTR (pDevice->pPacketDescBase) +
+					MM_UINT_PTR (pDevice->
+						     pRxJumboBdVirt[Idx].
+						     Opaque));
+
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+
+		Idx = (Idx + 1) & T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK;
+	}			/* while */
+
+	/* Reinitialize our copy of the indices. */
+	pDevice->RxJumboProdIdx = 0;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	MM_RELEASE_INT_LOCK (pDevice);
+
+	/* Initialize the statistis Block */
+	pDevice->pStatusBlkVirt->Status = 0;
+	pDevice->pStatusBlkVirt->RcvStdConIdx = 0;
+	pDevice->pStatusBlkVirt->RcvJumboConIdx = 0;
+	pDevice->pStatusBlkVirt->RcvMiniConIdx = 0;
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_Abort */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    Disable the interrupt and put the transmitter and receiver engines in   */
+/*    an idle state.  Aborts all pending send requests and receive buffers.   */
+/*    Also free all the receive buffers.                                      */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_Halt (PLM_DEVICE_BLOCK pDevice)
+{
+	PLM_PACKET pPacket;
+	LM_UINT32 EntryCnt;
+
+	LM_Abort (pDevice);
+
+	/* Get the number of entries in the queue. */
+	EntryCnt = QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container);
+
+	/* Make sure all the packets have been accounted for. */
+	for (EntryCnt = 0; EntryCnt < pDevice->RxPacketDescCnt; EntryCnt++) {
+		pPacket =
+		    (PLM_PACKET) QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
+		if (pPacket == 0)
+			break;
+
+		MM_FreeRxBuffer (pDevice, pPacket);
+
+		QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
+	}
+
+	LM_ResetChip (pDevice);
+
+	/* Restore PCI configuration registers. */
+	MM_WriteConfig32 (pDevice, PCI_CACHE_LINE_SIZE_REG,
+			  pDevice->SavedCacheLineReg);
+	LM_RegWrInd (pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG,
+		     (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId);
+
+	/* Reprogram the MAC address. */
+	LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_Halt */
+
+STATIC LM_STATUS LM_ResetChip (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+	/* Wait for access to the nvram interface before resetting.  This is */
+	/* a workaround to prevent EEPROM corruption. */
+	if (T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5700 &&
+	    T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5701) {
+		/* Request access to the flash interface. */
+		REG_WR (pDevice, Nvram.SwArb, SW_ARB_REQ_SET1);
+
+		for (j = 0; j < 100000; j++) {
+			Value32 = REG_RD (pDevice, Nvram.SwArb);
+			if (Value32 & SW_ARB_GNT1) {
+				break;
+			}
+			MM_Wait (10);
+		}
+	}
+
+	/* Global reset. */
+	REG_WR (pDevice, Grc.MiscCfg, GRC_MISC_CFG_CORE_CLOCK_RESET);
+	MM_Wait (40);
+	MM_Wait (40);
+	MM_Wait (40);
+
+	/* make sure we re-enable indirect accesses */
+	MM_WriteConfig32 (pDevice, T3_PCI_MISC_HOST_CTRL_REG,
+			  pDevice->MiscHostCtrl);
+
+	/* Set MAX PCI retry to zero. */
+	Value32 =
+	    T3_PCI_STATE_PCI_ROM_ENABLE | T3_PCI_STATE_PCI_ROM_RETRY_ENABLE;
+	if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) {
+		if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) {
+			Value32 |= T3_PCI_STATE_RETRY_SAME_DMA;
+		}
+	}
+	MM_WriteConfig32 (pDevice, T3_PCI_STATE_REG, Value32);
+
+	/* Restore PCI command register. */
+	MM_WriteConfig32 (pDevice, PCI_COMMAND_REG,
+			  pDevice->PciCommandStatusWords);
+
+	/* Disable PCI-X relaxed ordering bit. */
+	MM_ReadConfig32 (pDevice, PCIX_CAP_REG, &Value32);
+	Value32 &= ~PCIX_ENABLE_RELAXED_ORDERING;
+	MM_WriteConfig32 (pDevice, PCIX_CAP_REG, Value32);
+
+	/* Enable memory arbiter. */
+	REG_WR (pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE);
+
+#ifdef BIG_ENDIAN_PCI		/* This from jfd */
+	Value32 = GRC_MODE_WORD_SWAP_DATA | GRC_MODE_WORD_SWAP_NON_FRAME_DATA;
+#else
+#ifdef BIG_ENDIAN_HOST
+	/* Reconfigure the mode register. */
+	Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_WORD_SWAP_NON_FRAME_DATA |
+	    GRC_MODE_BYTE_SWAP_DATA | GRC_MODE_WORD_SWAP_DATA;
+#else
+	/* Reconfigure the mode register. */
+	Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA;
+#endif
+#endif
+	REG_WR (pDevice, Grc.Mode, Value32);
+
+	/* Prevent PXE from restarting. */
+	MEM_WR_OFFSET (pDevice, 0x0b50, T3_MAGIC_NUM);
+
+	if (pDevice->EnableTbi) {
+		pDevice->MacMode = MAC_MODE_PORT_MODE_TBI;
+		REG_WR (pDevice, MacCtrl.Mode, MAC_MODE_PORT_MODE_TBI);
+	} else {
+		REG_WR (pDevice, MacCtrl.Mode, 0);
+	}
+
+	/* Wait for the firmware to finish initialization. */
+	for (j = 0; j < 100000; j++) {
+		MM_Wait (10);
+
+		Value32 = MEM_RD_OFFSET (pDevice, 0x0b50);
+		if (Value32 == ~T3_MAGIC_NUM) {
+			break;
+		}
+	}
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+__inline static void LM_ServiceTxInterrupt (PLM_DEVICE_BLOCK pDevice)
+{
+	PLM_PACKET pPacket;
+	LM_UINT32 HwConIdx;
+	LM_UINT32 SwConIdx;
+
+	HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx;
+
+	/* Get our copy of the consumer index.  The buffer descriptors */
+	/* that are in between the consumer indices are freed. */
+	SwConIdx = pDevice->SendConIdx;
+
+	/* Move the packets from the TxPacketActiveQ that are sent out to */
+	/* the TxPacketXmittedQ.  Packets that are sent use the */
+	/* descriptors that are between SwConIdx and HwConIdx. */
+	while (SwConIdx != HwConIdx) {
+		/* Get the packet that was sent from the TxPacketActiveQ. */
+		pPacket =
+		    (PLM_PACKET) QQ_PopHead (&pDevice->TxPacketActiveQ.
+					     Container);
+
+		/* Set the return status. */
+		pPacket->PacketStatus = LM_STATUS_SUCCESS;
+
+		/* Put the packet in the TxPacketXmittedQ for indication later. */
+		QQ_PushTail (&pDevice->TxPacketXmittedQ.Container, pPacket);
+
+		/* Move to the next packet's BD. */
+		SwConIdx = (SwConIdx + pPacket->u.Tx.FragCount) &
+		    T3_SEND_RCB_ENTRY_COUNT_MASK;
+
+		/* Update the number of unused BDs. */
+		atomic_add (pPacket->u.Tx.FragCount, &pDevice->SendBdLeft);
+
+		/* Get the new updated HwConIdx. */
+		HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx;
+	}			/* while */
+
+	/* Save the new SwConIdx. */
+	pDevice->SendConIdx = SwConIdx;
+
+}				/* LM_ServiceTxInterrupt */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+__inline static void LM_ServiceRxInterrupt (PLM_DEVICE_BLOCK pDevice)
+{
+	PLM_PACKET pPacket;
+	PT3_RCV_BD pRcvBd;
+	LM_UINT32 HwRcvRetProdIdx;
+	LM_UINT32 SwRcvRetConIdx;
+
+	/* Loop thru the receive return rings for received packets. */
+	HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx;
+
+	SwRcvRetConIdx = pDevice->RcvRetConIdx;
+	while (SwRcvRetConIdx != HwRcvRetProdIdx) {
+		pRcvBd = &pDevice->pRcvRetBdVirt[SwRcvRetConIdx];
+
+		/* Get the received packet descriptor. */
+		pPacket = (PLM_PACKET) (MM_UINT_PTR (pDevice->pPacketDescBase) +
+					MM_UINT_PTR (pRcvBd->Opaque));
+
+		/* Check the error flag. */
+		if (pRcvBd->ErrorFlag &&
+		    pRcvBd->ErrorFlag != RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) {
+			pPacket->PacketStatus = LM_STATUS_FAILURE;
+
+			pDevice->RxCounters.RxPacketErrCnt++;
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_BAD_CRC) {
+				pDevice->RxCounters.RxErrCrcCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_COLL_DETECT) {
+				pDevice->RxCounters.RxErrCollCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_LINK_LOST_DURING_PKT) {
+				pDevice->RxCounters.RxErrLinkLostCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_PHY_DECODE_ERR) {
+				pDevice->RxCounters.RxErrPhyDecodeCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) {
+				pDevice->RxCounters.RxErrOddNibbleCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_MAC_ABORT) {
+				pDevice->RxCounters.RxErrMacAbortCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_LEN_LT_64) {
+				pDevice->RxCounters.RxErrShortPacketCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_TRUNC_NO_RESOURCES) {
+				pDevice->RxCounters.RxErrNoResourceCnt++;
+			}
+
+			if (pRcvBd->ErrorFlag & RCV_BD_ERR_GIANT_FRAME_RCVD) {
+				pDevice->RxCounters.RxErrLargePacketCnt++;
+			}
+		} else {
+			pPacket->PacketStatus = LM_STATUS_SUCCESS;
+			pPacket->PacketSize = pRcvBd->Len - 4;
+
+			pPacket->Flags = pRcvBd->Flags;
+			if (pRcvBd->Flags & RCV_BD_FLAG_VLAN_TAG) {
+				pPacket->VlanTag = pRcvBd->VlanTag;
+			}
+
+			pPacket->u.Rx.TcpUdpChecksum = pRcvBd->TcpUdpCksum;
+		}
+
+		/* Put the packet descriptor containing the received packet */
+		/* buffer in the RxPacketReceivedQ for indication later. */
+		QQ_PushTail (&pDevice->RxPacketReceivedQ.Container, pPacket);
+
+		/* Go to the next buffer descriptor. */
+		SwRcvRetConIdx = (SwRcvRetConIdx + 1) &
+		    T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK;
+
+		/* Get the updated HwRcvRetProdIdx. */
+		HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx;
+	}			/* while */
+
+	pDevice->RcvRetConIdx = SwRcvRetConIdx;
+
+	/* Update the receive return ring consumer index. */
+	MB_REG_WR (pDevice, Mailbox.RcvRetConIdx[0].Low, SwRcvRetConIdx);
+}				/* LM_ServiceRxInterrupt */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    This is the interrupt event handler routine. It acknowledges all        */
+/*    pending interrupts and process all pending events.                      */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_SUCCESS                                                       */
+/******************************************************************************/
+LM_STATUS LM_ServiceInterrupts (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+	int ServicePhyInt = FALSE;
+
+	/* Setup the phy chip whenever the link status changes. */
+	if (pDevice->LinkChngMode == T3_LINK_CHNG_MODE_USE_STATUS_REG) {
+		Value32 = REG_RD (pDevice, MacCtrl.Status);
+		if (pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) {
+			if (Value32 & MAC_STATUS_MI_INTERRUPT) {
+				ServicePhyInt = TRUE;
+			}
+		} else if (Value32 & MAC_STATUS_LINK_STATE_CHANGED) {
+			ServicePhyInt = TRUE;
+		}
+	} else {
+		if (pDevice->pStatusBlkVirt->
+		    Status & STATUS_BLOCK_LINK_CHANGED_STATUS) {
+			pDevice->pStatusBlkVirt->Status =
+			    STATUS_BLOCK_UPDATED | (pDevice->pStatusBlkVirt->
+						    Status &
+						    ~STATUS_BLOCK_LINK_CHANGED_STATUS);
+			ServicePhyInt = TRUE;
+		}
+	}
+#if INCLUDE_TBI_SUPPORT
+	if (pDevice->IgnoreTbiLinkChange == TRUE) {
+		ServicePhyInt = FALSE;
+	}
+#endif
+	if (ServicePhyInt == TRUE) {
+		LM_SetupPhy (pDevice);
+	}
+
+	/* Service receive and transmit interrupts. */
+	LM_ServiceRxInterrupt (pDevice);
+	LM_ServiceTxInterrupt (pDevice);
+
+	/* No spinlock for this queue since this routine is serialized. */
+	if (!QQ_Empty (&pDevice->RxPacketReceivedQ.Container)) {
+		/* Indicate receive packets. */
+		MM_IndicateRxPackets (pDevice);
+		/*       LM_QueueRxPackets(pDevice); */
+	}
+
+	/* No spinlock for this queue since this routine is serialized. */
+	if (!QQ_Empty (&pDevice->TxPacketXmittedQ.Container)) {
+		MM_IndicateTxPackets (pDevice);
+	}
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_ServiceInterrupts */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_MulticastAdd (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress)
+{
+	PLM_UINT8 pEntry;
+	LM_UINT32 j;
+
+	pEntry = pDevice->McTable[0];
+	for (j = 0; j < pDevice->McEntryCount; j++) {
+		if (IS_ETH_ADDRESS_EQUAL (pEntry, pMcAddress)) {
+			/* Found a match, increment the instance count. */
+			pEntry[LM_MC_INSTANCE_COUNT_INDEX] += 1;
+
+			return LM_STATUS_SUCCESS;
+		}
+
+		pEntry += LM_MC_ENTRY_SIZE;
+	}
+
+	if (pDevice->McEntryCount >= LM_MAX_MC_TABLE_SIZE) {
+		return LM_STATUS_FAILURE;
+	}
+
+	pEntry = pDevice->McTable[pDevice->McEntryCount];
+
+	COPY_ETH_ADDRESS (pMcAddress, pEntry);
+	pEntry[LM_MC_INSTANCE_COUNT_INDEX] = 1;
+
+	pDevice->McEntryCount++;
+
+	LM_SetReceiveMask (pDevice, pDevice->ReceiveMask | LM_ACCEPT_MULTICAST);
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_MulticastAdd */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_MulticastDel (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress)
+{
+	PLM_UINT8 pEntry;
+	LM_UINT32 j;
+
+	pEntry = pDevice->McTable[0];
+	for (j = 0; j < pDevice->McEntryCount; j++) {
+		if (IS_ETH_ADDRESS_EQUAL (pEntry, pMcAddress)) {
+			/* Found a match, decrement the instance count. */
+			pEntry[LM_MC_INSTANCE_COUNT_INDEX] -= 1;
+
+			/* No more instance left, remove the address from the table. */
+			/* Move the last entry in the table to the delete slot. */
+			if (pEntry[LM_MC_INSTANCE_COUNT_INDEX] == 0 &&
+			    pDevice->McEntryCount > 1) {
+
+				COPY_ETH_ADDRESS (pDevice->
+						  McTable[pDevice->
+							  McEntryCount - 1],
+						  pEntry);
+				pEntry[LM_MC_INSTANCE_COUNT_INDEX] =
+				    pDevice->McTable[pDevice->McEntryCount - 1]
+				    [LM_MC_INSTANCE_COUNT_INDEX];
+			}
+			pDevice->McEntryCount--;
+
+			/* Update the receive mask if the table is empty. */
+			if (pDevice->McEntryCount == 0) {
+				LM_SetReceiveMask (pDevice,
+						   pDevice->
+						   ReceiveMask &
+						   ~LM_ACCEPT_MULTICAST);
+			}
+
+			return LM_STATUS_SUCCESS;
+		}
+
+		pEntry += LM_MC_ENTRY_SIZE;
+	}
+
+	return LM_STATUS_FAILURE;
+}				/* LM_MulticastDel */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_MulticastClear (PLM_DEVICE_BLOCK pDevice)
+{
+	pDevice->McEntryCount = 0;
+
+	LM_SetReceiveMask (pDevice,
+			   pDevice->ReceiveMask & ~LM_ACCEPT_MULTICAST);
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_MulticastClear */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress)
+{
+	LM_UINT32 j;
+
+	for (j = 0; j < 4; j++) {
+		REG_WR (pDevice, MacCtrl.MacAddr[j].High,
+			(pMacAddress[0] << 8) | pMacAddress[1]);
+		REG_WR (pDevice, MacCtrl.MacAddr[j].Low,
+			(pMacAddress[2] << 24) | (pMacAddress[3] << 16) |
+			(pMacAddress[4] << 8) | pMacAddress[5]);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*    Sets up the default line speed, and duplex modes based on the requested */
+/*    media type.                                                             */
+/*                                                                            */
+/* Return:                                                                    */
+/*    None.                                                                   */
+/******************************************************************************/
+static LM_STATUS
+LM_TranslateRequestedMediaType (LM_REQUESTED_MEDIA_TYPE RequestedMediaType,
+				PLM_MEDIA_TYPE pMediaType,
+				PLM_LINE_SPEED pLineSpeed,
+				PLM_DUPLEX_MODE pDuplexMode)
+{
+	*pMediaType = LM_MEDIA_TYPE_AUTO;
+	*pLineSpeed = LM_LINE_SPEED_UNKNOWN;
+	*pDuplexMode = LM_DUPLEX_MODE_UNKNOWN;
+
+	/* determine media type */
+	switch (RequestedMediaType) {
+	case LM_REQUESTED_MEDIA_TYPE_BNC:
+		*pMediaType = LM_MEDIA_TYPE_BNC;
+		*pLineSpeed = LM_LINE_SPEED_10MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_AUTO:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_10MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_10MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_FULL;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_100MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_100MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_FULL;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_1000MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX:
+		*pMediaType = LM_MEDIA_TYPE_UTP;
+		*pLineSpeed = LM_LINE_SPEED_1000MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_FULL;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS:
+		*pMediaType = LM_MEDIA_TYPE_FIBER;
+		*pLineSpeed = LM_LINE_SPEED_100MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS_FULL_DUPLEX:
+		*pMediaType = LM_MEDIA_TYPE_FIBER;
+		*pLineSpeed = LM_LINE_SPEED_100MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_FULL;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS:
+		*pMediaType = LM_MEDIA_TYPE_FIBER;
+		*pLineSpeed = LM_LINE_SPEED_1000MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_HALF;
+		break;
+
+	case LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX:
+		*pMediaType = LM_MEDIA_TYPE_FIBER;
+		*pLineSpeed = LM_LINE_SPEED_1000MBPS;
+		*pDuplexMode = LM_DUPLEX_MODE_FULL;
+		break;
+
+	default:
+		break;
+	}			/* switch */
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_TranslateRequestedMediaType */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_LINK_ACTIVE                                                   */
+/*    LM_STATUS_LINK_DOWN                                                     */
+/******************************************************************************/
+static LM_STATUS LM_InitBcm540xPhy (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_LINE_SPEED CurrentLineSpeed;
+	LM_DUPLEX_MODE CurrentDuplexMode;
+	LM_STATUS CurrentLinkStatus;
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+#if 1				/* jmb: bugfix -- moved here, out of code that sets initial pwr state */
+	LM_WritePhy (pDevice, BCM5401_AUX_CTRL, 0x2);
+#endif
+	if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) {
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+
+		if (!pDevice->InitDone) {
+			Value32 = 0;
+		}
+
+		if (!(Value32 & PHY_STATUS_LINK_PASS)) {
+			LM_WritePhy (pDevice, BCM5401_AUX_CTRL, 0x0c20);
+
+			LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012);
+			LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x1804);
+
+			LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013);
+			LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x1204);
+
+			LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006);
+			LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0132);
+
+			LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006);
+			LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0232);
+
+			LM_WritePhy (pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f);
+			LM_WritePhy (pDevice, BCM540X_DSP_RW_PORT, 0x0a20);
+
+			LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+			for (j = 0; j < 1000; j++) {
+				MM_Wait (10);
+
+				LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+				if (Value32 & PHY_STATUS_LINK_PASS) {
+					MM_Wait (40);
+					break;
+				}
+			}
+
+			if ((pDevice->PhyId & PHY_ID_REV_MASK) ==
+			    PHY_BCM5401_B0_REV) {
+				if (!(Value32 & PHY_STATUS_LINK_PASS)
+				    && (pDevice->OldLineSpeed ==
+					LM_LINE_SPEED_1000MBPS)) {
+					LM_WritePhy (pDevice, PHY_CTRL_REG,
+						     PHY_CTRL_PHY_RESET);
+					for (j = 0; j < 100; j++) {
+						MM_Wait (10);
+
+						LM_ReadPhy (pDevice,
+							    PHY_CTRL_REG,
+							    &Value32);
+						if (!
+						    (Value32 &
+						     PHY_CTRL_PHY_RESET)) {
+							MM_Wait (40);
+							break;
+						}
+					}
+
+					LM_WritePhy (pDevice, BCM5401_AUX_CTRL,
+						     0x0c20);
+
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_ADDRESS_REG,
+						     0x0012);
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_RW_PORT,
+						     0x1804);
+
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_ADDRESS_REG,
+						     0x0013);
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_RW_PORT,
+						     0x1204);
+
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_ADDRESS_REG,
+						     0x8006);
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_RW_PORT,
+						     0x0132);
+
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_ADDRESS_REG,
+						     0x8006);
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_RW_PORT,
+						     0x0232);
+
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_ADDRESS_REG,
+						     0x201f);
+					LM_WritePhy (pDevice,
+						     BCM540X_DSP_RW_PORT,
+						     0x0a20);
+				}
+			}
+		}
+	} else if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+		   pDevice->ChipRevId == T3_CHIP_ID_5701_B0) {
+		/* Bug: 5701 A0, B0 TX CRC workaround. */
+		LM_WritePhy (pDevice, 0x15, 0x0a75);
+		LM_WritePhy (pDevice, 0x1c, 0x8c68);
+		LM_WritePhy (pDevice, 0x1c, 0x8d68);
+		LM_WritePhy (pDevice, 0x1c, 0x8c68);
+	}
+
+	/* Acknowledge interrupts. */
+	LM_ReadPhy (pDevice, BCM540X_INT_STATUS_REG, &Value32);
+	LM_ReadPhy (pDevice, BCM540X_INT_STATUS_REG, &Value32);
+
+	/* Configure the interrupt mask. */
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) {
+		LM_WritePhy (pDevice, BCM540X_INT_MASK_REG,
+			     ~BCM540X_INT_LINK_CHANGE);
+	}
+
+	/* Configure PHY led mode. */
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701 ||
+	    (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700)) {
+		if (pDevice->LedMode == LED_MODE_THREE_LINK) {
+			LM_WritePhy (pDevice, BCM540X_EXT_CTRL_REG,
+				     BCM540X_EXT_CTRL_LINK3_LED_MODE);
+		} else {
+			LM_WritePhy (pDevice, BCM540X_EXT_CTRL_REG, 0);
+		}
+	}
+
+	CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+
+	/* Get current link and duplex mode. */
+	for (j = 0; j < 100; j++) {
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+
+		if (Value32 & PHY_STATUS_LINK_PASS) {
+			break;
+		}
+		MM_Wait (40);
+	}
+
+	if (Value32 & PHY_STATUS_LINK_PASS) {
+
+		/* Determine the current line and duplex settings. */
+		LM_ReadPhy (pDevice, BCM540X_AUX_STATUS_REG, &Value32);
+		for (j = 0; j < 2000; j++) {
+			MM_Wait (10);
+
+			LM_ReadPhy (pDevice, BCM540X_AUX_STATUS_REG, &Value32);
+			if (Value32) {
+				break;
+			}
+		}
+
+		switch (Value32 & BCM540X_AUX_SPEED_MASK) {
+		case BCM540X_AUX_10BASET_HD:
+			CurrentLineSpeed = LM_LINE_SPEED_10MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_HALF;
+			break;
+
+		case BCM540X_AUX_10BASET_FD:
+			CurrentLineSpeed = LM_LINE_SPEED_10MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_FULL;
+			break;
+
+		case BCM540X_AUX_100BASETX_HD:
+			CurrentLineSpeed = LM_LINE_SPEED_100MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_HALF;
+			break;
+
+		case BCM540X_AUX_100BASETX_FD:
+			CurrentLineSpeed = LM_LINE_SPEED_100MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_FULL;
+			break;
+
+		case BCM540X_AUX_100BASET_HD:
+			CurrentLineSpeed = LM_LINE_SPEED_1000MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_HALF;
+			break;
+
+		case BCM540X_AUX_100BASET_FD:
+			CurrentLineSpeed = LM_LINE_SPEED_1000MBPS;
+			CurrentDuplexMode = LM_DUPLEX_MODE_FULL;
+			break;
+
+		default:
+
+			CurrentLineSpeed = LM_LINE_SPEED_UNKNOWN;
+			CurrentDuplexMode = LM_DUPLEX_MODE_UNKNOWN;
+			break;
+		}
+
+		/* Make sure we are in auto-neg mode. */
+		for (j = 0; j < 200; j++) {
+			LM_ReadPhy (pDevice, PHY_CTRL_REG, &Value32);
+			if (Value32 && Value32 != 0x7fff) {
+				break;
+			}
+
+			if (Value32 == 0 && pDevice->RequestedMediaType ==
+			    LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS) {
+				break;
+			}
+
+			MM_Wait (10);
+		}
+
+		/* Use the current line settings for "auto" mode. */
+		if (pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO
+		    || pDevice->RequestedMediaType ==
+		    LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) {
+			if (Value32 & PHY_CTRL_AUTO_NEG_ENABLE) {
+				CurrentLinkStatus = LM_STATUS_LINK_ACTIVE;
+
+				/* We may be exiting low power mode and the link is in */
+				/* 10mb.  In this case, we need to restart autoneg. */
+				LM_ReadPhy (pDevice, BCM540X_1000BASET_CTRL_REG,
+					    &Value32);
+				pDevice->advertising1000 = Value32;
+				/* 5702FE supports 10/100Mb only. */
+				if (T3_ASIC_REV (pDevice->ChipRevId) !=
+				    T3_ASIC_REV_5703
+				    || pDevice->BondId !=
+				    GRC_MISC_BD_ID_5702FE) {
+					if (!
+					    (Value32 &
+					     (BCM540X_AN_AD_1000BASET_HALF |
+					      BCM540X_AN_AD_1000BASET_FULL))) {
+						CurrentLinkStatus =
+						    LM_STATUS_LINK_SETTING_MISMATCH;
+					}
+				}
+			} else {
+				CurrentLinkStatus =
+				    LM_STATUS_LINK_SETTING_MISMATCH;
+			}
+		} else {
+			/* Force line settings. */
+			/* Use the current setting if it matches the user's requested */
+			/* setting. */
+			LM_ReadPhy (pDevice, PHY_CTRL_REG, &Value32);
+			if ((pDevice->LineSpeed == CurrentLineSpeed) &&
+			    (pDevice->DuplexMode == CurrentDuplexMode)) {
+				if ((pDevice->DisableAutoNeg &&
+				     !(Value32 & PHY_CTRL_AUTO_NEG_ENABLE)) ||
+				    (!pDevice->DisableAutoNeg &&
+				     (Value32 & PHY_CTRL_AUTO_NEG_ENABLE))) {
+					CurrentLinkStatus =
+					    LM_STATUS_LINK_ACTIVE;
+				} else {
+					CurrentLinkStatus =
+					    LM_STATUS_LINK_SETTING_MISMATCH;
+				}
+			} else {
+				CurrentLinkStatus =
+				    LM_STATUS_LINK_SETTING_MISMATCH;
+			}
+		}
+
+		/* Save line settings. */
+		pDevice->LineSpeed = CurrentLineSpeed;
+		pDevice->DuplexMode = CurrentDuplexMode;
+		pDevice->MediaType = LM_MEDIA_TYPE_UTP;
+	}
+
+	return CurrentLinkStatus;
+}				/* LM_InitBcm540xPhy */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS
+LM_SetFlowControl (PLM_DEVICE_BLOCK pDevice,
+		   LM_UINT32 LocalPhyAd, LM_UINT32 RemotePhyAd)
+{
+	LM_FLOW_CONTROL FlowCap;
+
+	/* Resolve flow control. */
+	FlowCap = LM_FLOW_CONTROL_NONE;
+
+	/* See Table 28B-3 of 802.3ab-1999 spec. */
+	if (pDevice->FlowControlCap & LM_FLOW_CONTROL_AUTO_PAUSE) {
+		if (LocalPhyAd & PHY_AN_AD_PAUSE_CAPABLE) {
+			if (LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) {
+				if (RemotePhyAd &
+				    PHY_LINK_PARTNER_PAUSE_CAPABLE) {
+					FlowCap =
+					    LM_FLOW_CONTROL_TRANSMIT_PAUSE |
+					    LM_FLOW_CONTROL_RECEIVE_PAUSE;
+				} else if (RemotePhyAd &
+					   PHY_LINK_PARTNER_ASYM_PAUSE) {
+					FlowCap = LM_FLOW_CONTROL_RECEIVE_PAUSE;
+				}
+			} else {
+				if (RemotePhyAd &
+				    PHY_LINK_PARTNER_PAUSE_CAPABLE) {
+					FlowCap =
+					    LM_FLOW_CONTROL_TRANSMIT_PAUSE |
+					    LM_FLOW_CONTROL_RECEIVE_PAUSE;
+				}
+			}
+		} else if (LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) {
+			if ((RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) &&
+			    (RemotePhyAd & PHY_LINK_PARTNER_ASYM_PAUSE)) {
+				FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE;
+			}
+		}
+	} else {
+		FlowCap = pDevice->FlowControlCap;
+	}
+
+	/* Enable/disable rx PAUSE. */
+	pDevice->RxMode &= ~RX_MODE_ENABLE_FLOW_CONTROL;
+	if (FlowCap & LM_FLOW_CONTROL_RECEIVE_PAUSE &&
+	    (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE ||
+	     pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE)) {
+		pDevice->FlowControl |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
+		pDevice->RxMode |= RX_MODE_ENABLE_FLOW_CONTROL;
+
+	}
+	REG_WR (pDevice, MacCtrl.RxMode, pDevice->RxMode);
+
+	/* Enable/disable tx PAUSE. */
+	pDevice->TxMode &= ~TX_MODE_ENABLE_FLOW_CONTROL;
+	if (FlowCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE &&
+	    (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE ||
+	     pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)) {
+		pDevice->FlowControl |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
+		pDevice->TxMode |= TX_MODE_ENABLE_FLOW_CONTROL;
+
+	}
+	REG_WR (pDevice, MacCtrl.TxMode, pDevice->TxMode);
+
+	return LM_STATUS_SUCCESS;
+}
+
+#if INCLUDE_TBI_SUPPORT
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+STATIC LM_STATUS LM_InitBcm800xPhy (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+	Value32 = REG_RD (pDevice, MacCtrl.Status);
+
+	/* Reset the SERDES during init and when we have link. */
+	if (!pDevice->InitDone || Value32 & MAC_STATUS_PCS_SYNCED) {
+		/* Set PLL lock range. */
+		LM_WritePhy (pDevice, 0x16, 0x8007);
+
+		/* Software reset. */
+		LM_WritePhy (pDevice, 0x00, 0x8000);
+
+		/* Wait for reset to complete. */
+		for (j = 0; j < 500; j++) {
+			MM_Wait (10);
+		}
+
+		/* Config mode; seletct PMA/Ch 1 regs. */
+		LM_WritePhy (pDevice, 0x10, 0x8411);
+
+		/* Enable auto-lock and comdet, select txclk for tx. */
+		LM_WritePhy (pDevice, 0x11, 0x0a10);
+
+		LM_WritePhy (pDevice, 0x18, 0x00a0);
+		LM_WritePhy (pDevice, 0x16, 0x41ff);
+
+		/* Assert and deassert POR. */
+		LM_WritePhy (pDevice, 0x13, 0x0400);
+		MM_Wait (40);
+		LM_WritePhy (pDevice, 0x13, 0x0000);
+
+		LM_WritePhy (pDevice, 0x11, 0x0a50);
+		MM_Wait (40);
+		LM_WritePhy (pDevice, 0x11, 0x0a10);
+
+		/* Delay for signal to stabilize. */
+		for (j = 0; j < 15000; j++) {
+			MM_Wait (10);
+		}
+
+		/* Deselect the channel register so we can read the PHY id later. */
+		LM_WritePhy (pDevice, 0x10, 0x8011);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+STATIC LM_STATUS LM_SetupFiberPhy (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_STATUS CurrentLinkStatus;
+	AUTONEG_STATUS AnStatus = 0;
+	LM_UINT32 Value32;
+	LM_UINT32 Cnt;
+	LM_UINT32 j, k;
+
+	pDevice->MacMode &= ~(MAC_MODE_HALF_DUPLEX | MAC_MODE_PORT_MODE_MASK);
+
+	/* Initialize the send_config register. */
+	REG_WR (pDevice, MacCtrl.TxAutoNeg, 0);
+
+	/* Enable TBI and full duplex mode. */
+	pDevice->MacMode |= MAC_MODE_PORT_MODE_TBI;
+	REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+
+	/* Initialize the BCM8002 SERDES PHY. */
+	switch (pDevice->PhyId & PHY_ID_MASK) {
+	case PHY_BCM8002_PHY_ID:
+		LM_InitBcm800xPhy (pDevice);
+		break;
+
+	default:
+		break;
+	}
+
+	/* Enable link change interrupt. */
+	REG_WR (pDevice, MacCtrl.MacEvent,
+		MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN);
+
+	/* Default to link down. */
+	CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+
+	/* Get the link status. */
+	Value32 = REG_RD (pDevice, MacCtrl.Status);
+	if (Value32 & MAC_STATUS_PCS_SYNCED) {
+		if ((pDevice->RequestedMediaType ==
+		     LM_REQUESTED_MEDIA_TYPE_AUTO)
+		    || (pDevice->DisableAutoNeg == FALSE)) {
+			/* auto-negotiation mode. */
+			/* Initialize the autoneg default capaiblities. */
+			AutonegInit (&pDevice->AnInfo);
+
+			/* Set the context pointer to point to the main device structure. */
+			pDevice->AnInfo.pContext = pDevice;
+
+			/* Setup flow control advertisement register. */
+			Value32 = GetPhyAdFlowCntrlSettings (pDevice);
+			if (Value32 & PHY_AN_AD_PAUSE_CAPABLE) {
+				pDevice->AnInfo.mr_adv_sym_pause = 1;
+			} else {
+				pDevice->AnInfo.mr_adv_sym_pause = 0;
+			}
+
+			if (Value32 & PHY_AN_AD_ASYM_PAUSE) {
+				pDevice->AnInfo.mr_adv_asym_pause = 1;
+			} else {
+				pDevice->AnInfo.mr_adv_asym_pause = 0;
+			}
+
+			/* Try to autoneg up to six times. */
+			if (pDevice->IgnoreTbiLinkChange) {
+				Cnt = 1;
+			} else {
+				Cnt = 6;
+			}
+			for (j = 0; j < Cnt; j++) {
+				REG_WR (pDevice, MacCtrl.TxAutoNeg, 0);
+
+				Value32 =
+				    pDevice->MacMode & ~MAC_MODE_PORT_MODE_MASK;
+				REG_WR (pDevice, MacCtrl.Mode, Value32);
+				MM_Wait (20);
+
+				REG_WR (pDevice, MacCtrl.Mode,
+					pDevice->
+					MacMode | MAC_MODE_SEND_CONFIGS);
+
+				MM_Wait (20);
+
+				pDevice->AnInfo.State = AN_STATE_UNKNOWN;
+				pDevice->AnInfo.CurrentTime_us = 0;
+
+				REG_WR (pDevice, Grc.Timer, 0);
+				for (k = 0;
+				     (pDevice->AnInfo.CurrentTime_us < 75000)
+				     && (k < 75000); k++) {
+					AnStatus =
+					    Autoneg8023z (&pDevice->AnInfo);
+
+					if ((AnStatus == AUTONEG_STATUS_DONE) ||
+					    (AnStatus == AUTONEG_STATUS_FAILED))
+					{
+						break;
+					}
+
+					pDevice->AnInfo.CurrentTime_us =
+					    REG_RD (pDevice, Grc.Timer);
+
+				}
+				if ((AnStatus == AUTONEG_STATUS_DONE) ||
+				    (AnStatus == AUTONEG_STATUS_FAILED)) {
+					break;
+				}
+				if (j >= 1) {
+					if (!(REG_RD (pDevice, MacCtrl.Status) &
+					      MAC_STATUS_PCS_SYNCED)) {
+						break;
+					}
+				}
+			}
+
+			/* Stop sending configs. */
+			MM_AnTxIdle (&pDevice->AnInfo);
+
+			/* Resolve flow control settings. */
+			if ((AnStatus == AUTONEG_STATUS_DONE) &&
+			    pDevice->AnInfo.mr_an_complete
+			    && pDevice->AnInfo.mr_link_ok
+			    && pDevice->AnInfo.mr_lp_adv_full_duplex) {
+				LM_UINT32 RemotePhyAd;
+				LM_UINT32 LocalPhyAd;
+
+				LocalPhyAd = 0;
+				if (pDevice->AnInfo.mr_adv_sym_pause) {
+					LocalPhyAd |= PHY_AN_AD_PAUSE_CAPABLE;
+				}
+
+				if (pDevice->AnInfo.mr_adv_asym_pause) {
+					LocalPhyAd |= PHY_AN_AD_ASYM_PAUSE;
+				}
+
+				RemotePhyAd = 0;
+				if (pDevice->AnInfo.mr_lp_adv_sym_pause) {
+					RemotePhyAd |=
+					    PHY_LINK_PARTNER_PAUSE_CAPABLE;
+				}
+
+				if (pDevice->AnInfo.mr_lp_adv_asym_pause) {
+					RemotePhyAd |=
+					    PHY_LINK_PARTNER_ASYM_PAUSE;
+				}
+
+				LM_SetFlowControl (pDevice, LocalPhyAd,
+						   RemotePhyAd);
+
+				CurrentLinkStatus = LM_STATUS_LINK_ACTIVE;
+			}
+			for (j = 0; j < 30; j++) {
+				MM_Wait (20);
+				REG_WR (pDevice, MacCtrl.Status,
+					MAC_STATUS_SYNC_CHANGED |
+					MAC_STATUS_CFG_CHANGED);
+				MM_Wait (20);
+				if ((REG_RD (pDevice, MacCtrl.Status) &
+				     (MAC_STATUS_SYNC_CHANGED |
+				      MAC_STATUS_CFG_CHANGED)) == 0)
+					break;
+			}
+			if (pDevice->PollTbiLink) {
+				Value32 = REG_RD (pDevice, MacCtrl.Status);
+				if (Value32 & MAC_STATUS_RECEIVING_CFG) {
+					pDevice->IgnoreTbiLinkChange = TRUE;
+				} else {
+					pDevice->IgnoreTbiLinkChange = FALSE;
+				}
+			}
+			Value32 = REG_RD (pDevice, MacCtrl.Status);
+			if (CurrentLinkStatus == LM_STATUS_LINK_DOWN &&
+			    (Value32 & MAC_STATUS_PCS_SYNCED) &&
+			    ((Value32 & MAC_STATUS_RECEIVING_CFG) == 0)) {
+				CurrentLinkStatus = LM_STATUS_LINK_ACTIVE;
+			}
+		} else {
+			/* We are forcing line speed. */
+			pDevice->FlowControlCap &= ~LM_FLOW_CONTROL_AUTO_PAUSE;
+			LM_SetFlowControl (pDevice, 0, 0);
+
+			CurrentLinkStatus = LM_STATUS_LINK_ACTIVE;
+			REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode |
+				MAC_MODE_SEND_CONFIGS);
+		}
+	}
+	/* Set the link polarity bit. */
+	pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY;
+	REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+
+	pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED |
+	    (pDevice->pStatusBlkVirt->
+	     Status & ~STATUS_BLOCK_LINK_CHANGED_STATUS);
+
+	for (j = 0; j < 100; j++) {
+		REG_WR (pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED |
+			MAC_STATUS_CFG_CHANGED);
+		MM_Wait (5);
+		if ((REG_RD (pDevice, MacCtrl.Status) &
+		     (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0)
+			break;
+	}
+
+	Value32 = REG_RD (pDevice, MacCtrl.Status);
+	if ((Value32 & MAC_STATUS_PCS_SYNCED) == 0) {
+		CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+		if (pDevice->DisableAutoNeg == FALSE) {
+			REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode |
+				MAC_MODE_SEND_CONFIGS);
+			MM_Wait (1);
+			REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+		}
+	}
+
+	/* Initialize the current link status. */
+	if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) {
+		pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS;
+		pDevice->DuplexMode = LM_DUPLEX_MODE_FULL;
+		REG_WR (pDevice, MacCtrl.LedCtrl, LED_CTRL_OVERRIDE_LINK_LED |
+			LED_CTRL_1000MBPS_LED_ON);
+	} else {
+		pDevice->LineSpeed = LM_LINE_SPEED_UNKNOWN;
+		pDevice->DuplexMode = LM_DUPLEX_MODE_UNKNOWN;
+		REG_WR (pDevice, MacCtrl.LedCtrl, LED_CTRL_OVERRIDE_LINK_LED |
+			LED_CTRL_OVERRIDE_TRAFFIC_LED);
+	}
+
+	/* Indicate link status. */
+	if (pDevice->LinkStatus != CurrentLinkStatus) {
+		pDevice->LinkStatus = CurrentLinkStatus;
+		MM_IndicateStatus (pDevice, CurrentLinkStatus);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+#endif				/* INCLUDE_TBI_SUPPORT */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_SetupCopperPhy (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_STATUS CurrentLinkStatus;
+	LM_UINT32 Value32;
+
+	/* Assume there is not link first. */
+	CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+
+	/* Disable phy link change attention. */
+	REG_WR (pDevice, MacCtrl.MacEvent, 0);
+
+	/* Clear link change attention. */
+	REG_WR (pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED |
+		MAC_STATUS_CFG_CHANGED);
+
+	/* Disable auto-polling for the moment. */
+	pDevice->MiMode = 0xc0000;
+	REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+	MM_Wait (40);
+
+	/* Determine the requested line speed and duplex. */
+	pDevice->OldLineSpeed = pDevice->LineSpeed;
+	LM_TranslateRequestedMediaType (pDevice->RequestedMediaType,
+					&pDevice->MediaType,
+					&pDevice->LineSpeed,
+					&pDevice->DuplexMode);
+
+	/* Initialize the phy chip. */
+	switch (pDevice->PhyId & PHY_ID_MASK) {
+	case PHY_BCM5400_PHY_ID:
+	case PHY_BCM5401_PHY_ID:
+	case PHY_BCM5411_PHY_ID:
+	case PHY_BCM5701_PHY_ID:
+	case PHY_BCM5703_PHY_ID:
+	case PHY_BCM5704_PHY_ID:
+		CurrentLinkStatus = LM_InitBcm540xPhy (pDevice);
+		break;
+
+	default:
+		break;
+	}
+
+	if (CurrentLinkStatus == LM_STATUS_LINK_SETTING_MISMATCH) {
+		CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+	}
+
+	/* Setup flow control. */
+	pDevice->FlowControl = LM_FLOW_CONTROL_NONE;
+	if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) {
+		LM_FLOW_CONTROL FlowCap;	/* Flow control capability. */
+
+		FlowCap = LM_FLOW_CONTROL_NONE;
+
+		if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) {
+			if (pDevice->DisableAutoNeg == FALSE ||
+			    pDevice->RequestedMediaType ==
+			    LM_REQUESTED_MEDIA_TYPE_AUTO
+			    || pDevice->RequestedMediaType ==
+			    LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) {
+				LM_UINT32 ExpectedPhyAd;
+				LM_UINT32 LocalPhyAd;
+				LM_UINT32 RemotePhyAd;
+
+				LM_ReadPhy (pDevice, PHY_AN_AD_REG,
+					    &LocalPhyAd);
+				pDevice->advertising = LocalPhyAd;
+				LocalPhyAd &=
+				    (PHY_AN_AD_ASYM_PAUSE |
+				     PHY_AN_AD_PAUSE_CAPABLE);
+
+				ExpectedPhyAd =
+				    GetPhyAdFlowCntrlSettings (pDevice);
+
+				if (LocalPhyAd != ExpectedPhyAd) {
+					CurrentLinkStatus = LM_STATUS_LINK_DOWN;
+				} else {
+					LM_ReadPhy (pDevice,
+						    PHY_LINK_PARTNER_ABILITY_REG,
+						    &RemotePhyAd);
+
+					LM_SetFlowControl (pDevice, LocalPhyAd,
+							   RemotePhyAd);
+				}
+			} else {
+				pDevice->FlowControlCap &=
+				    ~LM_FLOW_CONTROL_AUTO_PAUSE;
+				LM_SetFlowControl (pDevice, 0, 0);
+			}
+		}
+	}
+
+	if (CurrentLinkStatus == LM_STATUS_LINK_DOWN) {
+		LM_ForceAutoNeg (pDevice, pDevice->RequestedMediaType);
+
+		/* If we force line speed, we make get link right away. */
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+		LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+		if (Value32 & PHY_STATUS_LINK_PASS) {
+			CurrentLinkStatus = LM_STATUS_LINK_ACTIVE;
+		}
+	}
+
+	/* GMII interface. */
+	pDevice->MacMode &= ~MAC_MODE_PORT_MODE_MASK;
+	if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) {
+		if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS ||
+		    pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) {
+			pDevice->MacMode |= MAC_MODE_PORT_MODE_MII;
+		} else {
+			pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII;
+		}
+	} else {
+		pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII;
+	}
+
+	/* Set the MAC to operate in the appropriate duplex mode. */
+	pDevice->MacMode &= ~MAC_MODE_HALF_DUPLEX;
+	if (pDevice->DuplexMode == LM_DUPLEX_MODE_HALF) {
+		pDevice->MacMode |= MAC_MODE_HALF_DUPLEX;
+	}
+
+	/* Set the link polarity bit. */
+	pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY;
+	if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+		if ((pDevice->LedMode == LED_MODE_LINK10) ||
+		    (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE &&
+		     pDevice->LineSpeed == LM_LINE_SPEED_10MBPS)) {
+			pDevice->MacMode |= MAC_MODE_LINK_POLARITY;
+		}
+	} else {
+		if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) {
+			pDevice->MacMode |= MAC_MODE_LINK_POLARITY;
+		}
+
+		/* Set LED mode. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 = LED_CTRL_PHY_MODE_1;
+		} else {
+			if (pDevice->LedMode == LED_MODE_OUTPUT) {
+				Value32 = LED_CTRL_PHY_MODE_2;
+			} else {
+				Value32 = LED_CTRL_PHY_MODE_1;
+			}
+		}
+		REG_WR (pDevice, MacCtrl.LedCtrl, Value32);
+	}
+
+	REG_WR (pDevice, MacCtrl.Mode, pDevice->MacMode);
+
+	/* Enable auto polling. */
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		pDevice->MiMode |= MI_MODE_AUTO_POLLING_ENABLE;
+		REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+	}
+
+	/* Enable phy link change attention. */
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) {
+		REG_WR (pDevice, MacCtrl.MacEvent,
+			MAC_EVENT_ENABLE_MI_INTERRUPT);
+	} else {
+		REG_WR (pDevice, MacCtrl.MacEvent,
+			MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN);
+	}
+	if ((T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) &&
+	    (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) &&
+	    (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) &&
+	    (((pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) &&
+	      (pDevice->PciState & T3_PCI_STATE_BUS_SPEED_HIGH)) ||
+	     !(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE))) {
+		MM_Wait (120);
+		REG_WR (pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED |
+			MAC_STATUS_CFG_CHANGED);
+		MEM_WR_OFFSET (pDevice, T3_FIRMWARE_MAILBOX,
+			       T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE);
+	}
+
+	/* Indicate link status. */
+	if (pDevice->LinkStatus != CurrentLinkStatus) {
+		pDevice->LinkStatus = CurrentLinkStatus;
+		MM_IndicateStatus (pDevice, CurrentLinkStatus);
+	}
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_SetupCopperPhy */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_SetupPhy (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_STATUS LmStatus;
+	LM_UINT32 Value32;
+
+#if INCLUDE_TBI_SUPPORT
+	if (pDevice->EnableTbi) {
+		LmStatus = LM_SetupFiberPhy (pDevice);
+	} else
+#endif				/* INCLUDE_TBI_SUPPORT */
+	{
+		LmStatus = LM_SetupCopperPhy (pDevice);
+	}
+	if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) {
+		if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) {
+			Value32 = REG_RD (pDevice, PciCfg.PciState);
+			REG_WR (pDevice, PciCfg.PciState,
+				Value32 | T3_PCI_STATE_RETRY_SAME_DMA);
+		}
+	}
+	if ((pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) &&
+	    (pDevice->DuplexMode == LM_DUPLEX_MODE_HALF)) {
+		REG_WR (pDevice, MacCtrl.TxLengths, 0x26ff);
+	} else {
+		REG_WR (pDevice, MacCtrl.TxLengths, 0x2620);
+	}
+
+	return LmStatus;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_VOID
+LM_ReadPhy (PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, PLM_UINT32 pData32)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode &
+			~MI_MODE_AUTO_POLLING_ENABLE);
+		MM_Wait (40);
+	}
+
+	Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) |
+	    ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) <<
+	     MI_COM_FIRST_PHY_REG_ADDR_BIT) | MI_COM_CMD_READ | MI_COM_START;
+
+	REG_WR (pDevice, MacCtrl.MiCom, Value32);
+
+	for (j = 0; j < 20; j++) {
+		MM_Wait (25);
+
+		Value32 = REG_RD (pDevice, MacCtrl.MiCom);
+
+		if (!(Value32 & MI_COM_BUSY)) {
+			MM_Wait (5);
+			Value32 = REG_RD (pDevice, MacCtrl.MiCom);
+			Value32 &= MI_COM_PHY_DATA_MASK;
+			break;
+		}
+	}
+
+	if (Value32 & MI_COM_BUSY) {
+		Value32 = 0;
+	}
+
+	*pData32 = Value32;
+
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+		MM_Wait (40);
+	}
+}				/* LM_ReadPhy */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_VOID
+LM_WritePhy (PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, LM_UINT32 Data32)
+{
+	LM_UINT32 Value32;
+	LM_UINT32 j;
+
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode &
+			~MI_MODE_AUTO_POLLING_ENABLE);
+		MM_Wait (40);
+	}
+
+	Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) |
+	    ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) <<
+	     MI_COM_FIRST_PHY_REG_ADDR_BIT) | (Data32 & MI_COM_PHY_DATA_MASK) |
+	    MI_COM_CMD_WRITE | MI_COM_START;
+
+	REG_WR (pDevice, MacCtrl.MiCom, Value32);
+
+	for (j = 0; j < 20; j++) {
+		MM_Wait (25);
+
+		Value32 = REG_RD (pDevice, MacCtrl.MiCom);
+
+		if (!(Value32 & MI_COM_BUSY)) {
+			MM_Wait (5);
+			break;
+		}
+	}
+
+	if (pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) {
+		REG_WR (pDevice, MacCtrl.MiMode, pDevice->MiMode);
+		MM_Wait (40);
+	}
+}				/* LM_WritePhy */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_SetPowerState (PLM_DEVICE_BLOCK pDevice, LM_POWER_STATE PowerLevel)
+{
+	LM_UINT32 PmeSupport;
+	LM_UINT32 Value32;
+	LM_UINT32 PmCtrl;
+
+	/* make sureindirect accesses are enabled */
+	MM_WriteConfig32 (pDevice, T3_PCI_MISC_HOST_CTRL_REG,
+			  pDevice->MiscHostCtrl);
+
+	/* Clear the PME_ASSERT bit and the power state bits.  Also enable */
+	/* the PME bit. */
+	MM_ReadConfig32 (pDevice, T3_PCI_PM_STATUS_CTRL_REG, &PmCtrl);
+
+	PmCtrl |= T3_PM_PME_ASSERTED;
+	PmCtrl &= ~T3_PM_POWER_STATE_MASK;
+
+	/* Set the appropriate power state. */
+	if (PowerLevel == LM_POWER_STATE_D0) {
+
+		/* Bring the card out of low power mode. */
+		PmCtrl |= T3_PM_POWER_STATE_D0;
+		MM_WriteConfig32 (pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl);
+
+		REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl);
+		MM_Wait (40);
+#if 0				/* Bugfix by jmb...can't call WritePhy here because pDevice not fully initialized */
+		LM_WritePhy (pDevice, BCM5401_AUX_CTRL, 0x02);
+#endif
+
+		return LM_STATUS_SUCCESS;
+	} else if (PowerLevel == LM_POWER_STATE_D1) {
+		PmCtrl |= T3_PM_POWER_STATE_D1;
+	} else if (PowerLevel == LM_POWER_STATE_D2) {
+		PmCtrl |= T3_PM_POWER_STATE_D2;
+	} else if (PowerLevel == LM_POWER_STATE_D3) {
+		PmCtrl |= T3_PM_POWER_STATE_D3;
+	} else {
+		return LM_STATUS_FAILURE;
+	}
+	PmCtrl |= T3_PM_PME_ENABLE;
+
+	/* Mask out all interrupts so LM_SetupPhy won't be called while we are */
+	/* setting new line speed. */
+	Value32 = REG_RD (pDevice, PciCfg.MiscHostCtrl);
+	REG_WR (pDevice, PciCfg.MiscHostCtrl,
+		Value32 | MISC_HOST_CTRL_MASK_PCI_INT);
+
+	if (!pDevice->RestoreOnWakeUp) {
+		pDevice->RestoreOnWakeUp = TRUE;
+		pDevice->WakeUpDisableAutoNeg = pDevice->DisableAutoNeg;
+		pDevice->WakeUpRequestedMediaType = pDevice->RequestedMediaType;
+	}
+
+	/* Force auto-negotiation to 10 line speed. */
+	pDevice->DisableAutoNeg = FALSE;
+	pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
+	LM_SetupPhy (pDevice);
+
+	/* Put the driver in the initial state, and go through the power down */
+	/* sequence. */
+	LM_Halt (pDevice);
+
+	MM_ReadConfig32 (pDevice, T3_PCI_PM_CAP_REG, &PmeSupport);
+
+	if (pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE) {
+
+		/* Enable WOL. */
+		LM_WritePhy (pDevice, BCM5401_AUX_CTRL, 0x5a);
+		MM_Wait (40);
+
+		/* Set LED mode. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 = LED_CTRL_PHY_MODE_1;
+		} else {
+			if (pDevice->LedMode == LED_MODE_OUTPUT) {
+				Value32 = LED_CTRL_PHY_MODE_2;
+			} else {
+				Value32 = LED_CTRL_PHY_MODE_1;
+			}
+		}
+
+		Value32 = MAC_MODE_PORT_MODE_MII;
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700) {
+			if (pDevice->LedMode == LED_MODE_LINK10 ||
+			    pDevice->WolSpeed == WOL_SPEED_10MB) {
+				Value32 |= MAC_MODE_LINK_POLARITY;
+			}
+		} else {
+			Value32 |= MAC_MODE_LINK_POLARITY;
+		}
+		REG_WR (pDevice, MacCtrl.Mode, Value32);
+		MM_Wait (40);
+		MM_Wait (40);
+		MM_Wait (40);
+
+		/* Always enable magic packet wake-up if we have vaux. */
+		if ((PmeSupport & T3_PCI_PM_CAP_PME_D3COLD) &&
+		    (pDevice->WakeUpModeCap & LM_WAKE_UP_MODE_MAGIC_PACKET)) {
+			Value32 |= MAC_MODE_DETECT_MAGIC_PACKET_ENABLE;
+		}
+
+		REG_WR (pDevice, MacCtrl.Mode, Value32);
+
+		/* Enable the receiver. */
+		REG_WR (pDevice, MacCtrl.RxMode, RX_MODE_ENABLE);
+	}
+
+	/* Disable tx/rx clocks, and seletect an alternate clock. */
+	if (pDevice->WolSpeed == WOL_SPEED_100MB) {
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 =
+			    T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK |
+			    T3_PCI_SELECT_ALTERNATE_CLOCK;
+		} else {
+			Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK;
+		}
+		REG_WR (pDevice, PciCfg.ClockCtrl, Value32);
+
+		MM_Wait (40);
+
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 =
+			    T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK |
+			    T3_PCI_SELECT_ALTERNATE_CLOCK |
+			    T3_PCI_44MHZ_CORE_CLOCK;
+		} else {
+			Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK |
+			    T3_PCI_44MHZ_CORE_CLOCK;
+		}
+
+		REG_WR (pDevice, PciCfg.ClockCtrl, Value32);
+
+		MM_Wait (40);
+
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 =
+			    T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK |
+			    T3_PCI_44MHZ_CORE_CLOCK;
+		} else {
+			Value32 = T3_PCI_44MHZ_CORE_CLOCK;
+		}
+
+		REG_WR (pDevice, PciCfg.ClockCtrl, Value32);
+	} else {
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			Value32 =
+			    T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK |
+			    T3_PCI_SELECT_ALTERNATE_CLOCK |
+			    T3_PCI_POWER_DOWN_PCI_PLL133;
+		} else {
+			Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK |
+			    T3_PCI_POWER_DOWN_PCI_PLL133;
+		}
+
+		REG_WR (pDevice, PciCfg.ClockCtrl, Value32);
+	}
+
+	MM_Wait (40);
+
+	if (!pDevice->EepromWp
+	    && (pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE)) {
+		/* Switch adapter to auxilliary power. */
+		if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
+		    T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
+			/* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */
+			REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE2 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1);
+			MM_Wait (40);
+		} else {
+			/* GPIO0 = 0, GPIO1 = 1, GPIO2 = 1. */
+			REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE2 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2);
+			MM_Wait (40);
+
+			/* GPIO0 = 1, GPIO1 = 1, GPIO2 = 1. */
+			REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE2 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2);
+			MM_Wait (40);
+
+			/* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */
+			REG_WR (pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE1 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OE2 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 |
+				GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1);
+			MM_Wait (40);
+		}
+	}
+
+	/* Set the phy to low power mode. */
+	/* Put the the hardware in low power mode. */
+	MM_WriteConfig32 (pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl);
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_SetPowerState */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+static LM_UINT32 GetPhyAdFlowCntrlSettings (PLM_DEVICE_BLOCK pDevice)
+{
+	LM_UINT32 Value32;
+
+	Value32 = 0;
+
+	/* Auto negotiation flow control only when autonegotiation is enabled. */
+	if (pDevice->DisableAutoNeg == FALSE ||
+	    pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO ||
+	    pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) {
+		/* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */
+		if ((pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE) ||
+		    ((pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE)
+		     && (pDevice->
+			 FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE))) {
+			Value32 |= PHY_AN_AD_PAUSE_CAPABLE;
+		} else if (pDevice->
+			   FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE) {
+			Value32 |= PHY_AN_AD_ASYM_PAUSE;
+		} else if (pDevice->
+			   FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
+			Value32 |=
+			    PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE;
+		}
+	}
+
+	return Value32;
+}
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/*    LM_STATUS_FAILURE                                                       */
+/*    LM_STATUS_SUCCESS                                                       */
+/*                                                                            */
+/******************************************************************************/
+static LM_STATUS
+LM_ForceAutoNegBcm540xPhy (PLM_DEVICE_BLOCK pDevice,
+			   LM_REQUESTED_MEDIA_TYPE RequestedMediaType)
+{
+	LM_MEDIA_TYPE MediaType;
+	LM_LINE_SPEED LineSpeed;
+	LM_DUPLEX_MODE DuplexMode;
+	LM_UINT32 NewPhyCtrl;
+	LM_UINT32 Value32;
+	LM_UINT32 Cnt;
+
+	/* Get the interface type, line speed, and duplex mode. */
+	LM_TranslateRequestedMediaType (RequestedMediaType, &MediaType,
+					&LineSpeed, &DuplexMode);
+
+	if (pDevice->RestoreOnWakeUp) {
+		LM_WritePhy (pDevice, BCM540X_1000BASET_CTRL_REG, 0);
+		pDevice->advertising1000 = 0;
+		Value32 = PHY_AN_AD_10BASET_FULL | PHY_AN_AD_10BASET_HALF;
+		if (pDevice->WolSpeed == WOL_SPEED_100MB) {
+			Value32 |=
+			    PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF;
+		}
+		Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
+		Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+		LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+		pDevice->advertising = Value32;
+	}
+	/* Setup the auto-negotiation advertisement register. */
+	else if (LineSpeed == LM_LINE_SPEED_UNKNOWN) {
+		/* Setup the 10/100 Mbps auto-negotiation advertisement register. */
+		Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD |
+		    PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL |
+		    PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF;
+		Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+
+		LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+		pDevice->advertising = Value32;
+
+		/* Advertise 1000Mbps */
+		Value32 =
+		    BCM540X_AN_AD_1000BASET_HALF | BCM540X_AN_AD_1000BASET_FULL;
+
+#if INCLUDE_5701_AX_FIX
+		/* Bug: workaround for CRC error in gigabit mode when we are in */
+		/* slave mode.  This will force the PHY to operate in */
+		/* master mode. */
+		if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 ||
+		    pDevice->ChipRevId == T3_CHIP_ID_5701_B0) {
+			Value32 |= BCM540X_CONFIG_AS_MASTER |
+			    BCM540X_ENABLE_CONFIG_AS_MASTER;
+		}
+#endif
+
+		LM_WritePhy (pDevice, BCM540X_1000BASET_CTRL_REG, Value32);
+		pDevice->advertising1000 = Value32;
+	} else {
+		if (LineSpeed == LM_LINE_SPEED_1000MBPS) {
+			Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
+			Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+
+			LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+			pDevice->advertising = Value32;
+
+			if (DuplexMode != LM_DUPLEX_MODE_FULL) {
+				Value32 = BCM540X_AN_AD_1000BASET_HALF;
+			} else {
+				Value32 = BCM540X_AN_AD_1000BASET_FULL;
+			}
+
+			LM_WritePhy (pDevice, BCM540X_1000BASET_CTRL_REG,
+				     Value32);
+			pDevice->advertising1000 = Value32;
+		} else if (LineSpeed == LM_LINE_SPEED_100MBPS) {
+			LM_WritePhy (pDevice, BCM540X_1000BASET_CTRL_REG, 0);
+			pDevice->advertising1000 = 0;
+
+			if (DuplexMode != LM_DUPLEX_MODE_FULL) {
+				Value32 = PHY_AN_AD_100BASETX_HALF;
+			} else {
+				Value32 = PHY_AN_AD_100BASETX_FULL;
+			}
+
+			Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
+			Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+
+			LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+			pDevice->advertising = Value32;
+		} else if (LineSpeed == LM_LINE_SPEED_10MBPS) {
+			LM_WritePhy (pDevice, BCM540X_1000BASET_CTRL_REG, 0);
+			pDevice->advertising1000 = 0;
+
+			if (DuplexMode != LM_DUPLEX_MODE_FULL) {
+				Value32 = PHY_AN_AD_10BASET_HALF;
+			} else {
+				Value32 = PHY_AN_AD_10BASET_FULL;
+			}
+
+			Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
+			Value32 |= GetPhyAdFlowCntrlSettings (pDevice);
+
+			LM_WritePhy (pDevice, PHY_AN_AD_REG, Value32);
+			pDevice->advertising = Value32;
+		}
+	}
+
+	/* Force line speed if auto-negotiation is disabled. */
+	if (pDevice->DisableAutoNeg && LineSpeed != LM_LINE_SPEED_UNKNOWN) {
+		/* This code path is executed only when there is link. */
+		pDevice->MediaType = MediaType;
+		pDevice->LineSpeed = LineSpeed;
+		pDevice->DuplexMode = DuplexMode;
+
+		/* Force line seepd. */
+		NewPhyCtrl = 0;
+		switch (LineSpeed) {
+		case LM_LINE_SPEED_10MBPS:
+			NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_10MBPS;
+			break;
+		case LM_LINE_SPEED_100MBPS:
+			NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_100MBPS;
+			break;
+		case LM_LINE_SPEED_1000MBPS:
+			NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS;
+			break;
+		default:
+			NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS;
+			break;
+		}
+
+		if (DuplexMode == LM_DUPLEX_MODE_FULL) {
+			NewPhyCtrl |= PHY_CTRL_FULL_DUPLEX_MODE;
+		}
+
+		/* Don't do anything if the PHY_CTRL is already what we wanted. */
+		LM_ReadPhy (pDevice, PHY_CTRL_REG, &Value32);
+		if (Value32 != NewPhyCtrl) {
+			/* Temporary bring the link down before forcing line speed. */
+			LM_WritePhy (pDevice, PHY_CTRL_REG,
+				     PHY_CTRL_LOOPBACK_MODE);
+
+			/* Wait for link to go down. */
+			for (Cnt = 0; Cnt < 15000; Cnt++) {
+				MM_Wait (10);
+
+				LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+				LM_ReadPhy (pDevice, PHY_STATUS_REG, &Value32);
+
+				if (!(Value32 & PHY_STATUS_LINK_PASS)) {
+					MM_Wait (40);
+					break;
+				}
+			}
+
+			LM_WritePhy (pDevice, PHY_CTRL_REG, NewPhyCtrl);
+			MM_Wait (40);
+		}
+	} else {
+		LM_WritePhy (pDevice, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE |
+			     PHY_CTRL_RESTART_AUTO_NEG);
+	}
+
+	return LM_STATUS_SUCCESS;
+}				/* LM_ForceAutoNegBcm540xPhy */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+static LM_STATUS
+LM_ForceAutoNeg (PLM_DEVICE_BLOCK pDevice,
+		 LM_REQUESTED_MEDIA_TYPE RequestedMediaType)
+{
+	LM_STATUS LmStatus;
+
+	/* Initialize the phy chip. */
+	switch (pDevice->PhyId & PHY_ID_MASK) {
+	case PHY_BCM5400_PHY_ID:
+	case PHY_BCM5401_PHY_ID:
+	case PHY_BCM5411_PHY_ID:
+	case PHY_BCM5701_PHY_ID:
+	case PHY_BCM5703_PHY_ID:
+	case PHY_BCM5704_PHY_ID:
+		LmStatus =
+		    LM_ForceAutoNegBcm540xPhy (pDevice, RequestedMediaType);
+		break;
+
+	default:
+		LmStatus = LM_STATUS_FAILURE;
+		break;
+	}
+
+	return LmStatus;
+}				/* LM_ForceAutoNeg */
+
+/******************************************************************************/
+/* Description:                                                               */
+/*                                                                            */
+/* Return:                                                                    */
+/******************************************************************************/
+LM_STATUS LM_LoadFirmware (PLM_DEVICE_BLOCK pDevice,
+			   PT3_FWIMG_INFO pFwImg,
+			   LM_UINT32 LoadCpu, LM_UINT32 StartCpu)
+{
+	LM_UINT32 i;
+	LM_UINT32 address;
+
+	if (LoadCpu & T3_RX_CPU_ID) {
+		if (LM_HaltCpu (pDevice, T3_RX_CPU_ID) != LM_STATUS_SUCCESS) {
+			return LM_STATUS_FAILURE;
+		}
+
+		/* First of all clear scrach pad memory */
+		for (i = 0; i < T3_RX_CPU_SPAD_SIZE; i += 4) {
+			LM_RegWrInd (pDevice, T3_RX_CPU_SPAD_ADDR + i, 0);
+		}
+
+		/* Copy code first */
+		address = T3_RX_CPU_SPAD_ADDR + (pFwImg->Text.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->Text.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->Text.Buffer)[i /
+									 4]);
+		}
+
+		address =
+		    T3_RX_CPU_SPAD_ADDR + (pFwImg->ROnlyData.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->ROnlyData.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->ROnlyData.
+				      Buffer)[i / 4]);
+		}
+
+		address = T3_RX_CPU_SPAD_ADDR + (pFwImg->Data.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->Data.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->Data.Buffer)[i /
+									 4]);
+		}
+	}
+
+	if (LoadCpu & T3_TX_CPU_ID) {
+		if (LM_HaltCpu (pDevice, T3_TX_CPU_ID) != LM_STATUS_SUCCESS) {
+			return LM_STATUS_FAILURE;
+		}
+
+		/* First of all clear scrach pad memory */
+		for (i = 0; i < T3_TX_CPU_SPAD_SIZE; i += 4) {
+			LM_RegWrInd (pDevice, T3_TX_CPU_SPAD_ADDR + i, 0);
+		}
+
+		/* Copy code first */
+		address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Text.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->Text.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->Text.Buffer)[i /
+									 4]);
+		}
+
+		address =
+		    T3_TX_CPU_SPAD_ADDR + (pFwImg->ROnlyData.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->ROnlyData.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->ROnlyData.
+				      Buffer)[i / 4]);
+		}
+
+		address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Data.Offset & 0xffff);
+		for (i = 0; i <= pFwImg->Data.Length; i += 4) {
+			LM_RegWrInd (pDevice, address + i,
+				     ((LM_UINT32 *) pFwImg->Data.Buffer)[i /
+									 4]);
+		}
+	}
+
+	if (StartCpu & T3_RX_CPU_ID) {
+		/* Start Rx CPU */
+		REG_WR (pDevice, rxCpu.reg.state, 0xffffffff);
+		REG_WR (pDevice, rxCpu.reg.PC, pFwImg->StartAddress);
+		for (i = 0; i < 5; i++) {
+			if (pFwImg->StartAddress ==
+			    REG_RD (pDevice, rxCpu.reg.PC))
+				break;
+
+			REG_WR (pDevice, rxCpu.reg.state, 0xffffffff);
+			REG_WR (pDevice, rxCpu.reg.mode, CPU_MODE_HALT);
+			REG_WR (pDevice, rxCpu.reg.PC, pFwImg->StartAddress);
+			MM_Wait (1000);
+		}
+
+		REG_WR (pDevice, rxCpu.reg.state, 0xffffffff);
+		REG_WR (pDevice, rxCpu.reg.mode, 0);
+	}
+
+	if (StartCpu & T3_TX_CPU_ID) {
+		/* Start Tx CPU */
+		REG_WR (pDevice, txCpu.reg.state, 0xffffffff);
+		REG_WR (pDevice, txCpu.reg.PC, pFwImg->StartAddress);
+		for (i = 0; i < 5; i++) {
+			if (pFwImg->StartAddress ==
+			    REG_RD (pDevice, txCpu.reg.PC))
+				break;
+
+			REG_WR (pDevice, txCpu.reg.state, 0xffffffff);
+			REG_WR (pDevice, txCpu.reg.mode, CPU_MODE_HALT);
+			REG_WR (pDevice, txCpu.reg.PC, pFwImg->StartAddress);
+			MM_Wait (1000);
+		}
+
+		REG_WR (pDevice, txCpu.reg.state, 0xffffffff);
+		REG_WR (pDevice, txCpu.reg.mode, 0);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+STATIC LM_STATUS LM_HaltCpu (PLM_DEVICE_BLOCK pDevice, LM_UINT32 cpu_number)
+{
+	LM_UINT32 i;
+
+	if (cpu_number == T3_RX_CPU_ID) {
+		for (i = 0; i < 10000; i++) {
+			REG_WR (pDevice, rxCpu.reg.state, 0xffffffff);
+			REG_WR (pDevice, rxCpu.reg.mode, CPU_MODE_HALT);
+
+			if (REG_RD (pDevice, rxCpu.reg.mode) & CPU_MODE_HALT)
+				break;
+		}
+
+		REG_WR (pDevice, rxCpu.reg.state, 0xffffffff);
+		REG_WR (pDevice, rxCpu.reg.mode, CPU_MODE_HALT);
+		MM_Wait (10);
+	} else {
+		for (i = 0; i < 10000; i++) {
+			REG_WR (pDevice, txCpu.reg.state, 0xffffffff);
+			REG_WR (pDevice, txCpu.reg.mode, CPU_MODE_HALT);
+
+			if (REG_RD (pDevice, txCpu.reg.mode) & CPU_MODE_HALT)
+				break;
+		}
+	}
+
+	return ((i == 10000) ? LM_STATUS_FAILURE : LM_STATUS_SUCCESS);
+}
+
+int LM_BlinkLED (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDurationSec)
+{
+	LM_UINT32 Oldcfg;
+	int j;
+	int ret = 0;
+
+	if (BlinkDurationSec == 0) {
+		return 0;
+	}
+	if (BlinkDurationSec > 120) {
+		BlinkDurationSec = 120;
+	}
+
+	Oldcfg = REG_RD (pDevice, MacCtrl.LedCtrl);
+	for (j = 0; j < BlinkDurationSec * 2; j++) {
+		if (j % 2) {
+			/* Turn on the LEDs. */
+			REG_WR (pDevice, MacCtrl.LedCtrl,
+				LED_CTRL_OVERRIDE_LINK_LED |
+				LED_CTRL_1000MBPS_LED_ON |
+				LED_CTRL_100MBPS_LED_ON |
+				LED_CTRL_10MBPS_LED_ON |
+				LED_CTRL_OVERRIDE_TRAFFIC_LED |
+				LED_CTRL_BLINK_TRAFFIC_LED |
+				LED_CTRL_TRAFFIC_LED);
+		} else {
+			/* Turn off the LEDs. */
+			REG_WR (pDevice, MacCtrl.LedCtrl,
+				LED_CTRL_OVERRIDE_LINK_LED |
+				LED_CTRL_OVERRIDE_TRAFFIC_LED);
+		}
+
+#ifndef EMBEDDED
+		current->state = TASK_INTERRUPTIBLE;
+		if (schedule_timeout (HZ / 2) != 0) {
+			ret = -EINTR;
+			break;
+		}
+#else
+		udelay (100000);	/* 1s sleep */
+#endif
+	}
+	REG_WR (pDevice, MacCtrl.LedCtrl, Oldcfg);
+	return ret;
+}
+
+int t3_do_dma (PLM_DEVICE_BLOCK pDevice,
+	       LM_PHYSICAL_ADDRESS host_addr_phy, int length, int dma_read)
+{
+	T3_DMA_DESC dma_desc;
+	int i;
+	LM_UINT32 dma_desc_addr;
+	LM_UINT32 value32;
+
+	REG_WR (pDevice, BufMgr.Mode, 0);
+	REG_WR (pDevice, Ftq.Reset, 0);
+
+	dma_desc.host_addr.High = host_addr_phy.High;
+	dma_desc.host_addr.Low = host_addr_phy.Low;
+	dma_desc.nic_mbuf = 0x2100;
+	dma_desc.len = length;
+	dma_desc.flags = 0x00000004;	/* Generate Rx-CPU event */
+
+	if (dma_read) {
+		dma_desc.cqid_sqid = (T3_QID_RX_BD_COMP << 8) |
+		    T3_QID_DMA_HIGH_PRI_READ;
+		REG_WR (pDevice, DmaRead.Mode, DMA_READ_MODE_ENABLE);
+	} else {
+		dma_desc.cqid_sqid = (T3_QID_RX_DATA_COMP << 8) |
+		    T3_QID_DMA_HIGH_PRI_WRITE;
+		REG_WR (pDevice, DmaWrite.Mode, DMA_WRITE_MODE_ENABLE);
+	}
+
+	dma_desc_addr = T3_NIC_DMA_DESC_POOL_ADDR;
+
+	/* Writing this DMA descriptor to DMA memory */
+	for (i = 0; i < sizeof (T3_DMA_DESC); i += 4) {
+		value32 = *((PLM_UINT32) (((PLM_UINT8) & dma_desc) + i));
+		MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_ADDR_REG,
+				  dma_desc_addr + i);
+		MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_DATA_REG,
+				  cpu_to_le32 (value32));
+	}
+	MM_WriteConfig32 (pDevice, T3_PCI_MEM_WIN_ADDR_REG, 0);
+
+	if (dma_read)
+		REG_WR (pDevice, Ftq.DmaHighReadFtqFifoEnqueueDequeue,
+			dma_desc_addr);
+	else
+		REG_WR (pDevice, Ftq.DmaHighWriteFtqFifoEnqueueDequeue,
+			dma_desc_addr);
+
+	for (i = 0; i < 40; i++) {
+		if (dma_read)
+			value32 =
+			    REG_RD (pDevice,
+				    Ftq.RcvBdCompFtqFifoEnqueueDequeue);
+		else
+			value32 =
+			    REG_RD (pDevice,
+				    Ftq.RcvDataCompFtqFifoEnqueueDequeue);
+
+		if ((value32 & 0xffff) == dma_desc_addr)
+			break;
+
+		MM_Wait (10);
+	}
+
+	return LM_STATUS_SUCCESS;
+}
+
+STATIC LM_STATUS
+LM_DmaTest (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt,
+	    LM_PHYSICAL_ADDRESS BufferPhy, LM_UINT32 BufferSize)
+{
+	int j;
+	LM_UINT32 *ptr;
+	int dma_success = 0;
+
+	if (T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5700 &&
+	    T3_ASIC_REV (pDevice->ChipRevId) != T3_ASIC_REV_5701) {
+		return LM_STATUS_SUCCESS;
+	}
+	while (!dma_success) {
+		/* Fill data with incremental patterns */
+		ptr = (LM_UINT32 *) pBufferVirt;
+		for (j = 0; j < BufferSize / 4; j++)
+			*ptr++ = j;
+
+		if (t3_do_dma (pDevice, BufferPhy, BufferSize, 1) ==
+		    LM_STATUS_FAILURE) {
+			return LM_STATUS_FAILURE;
+		}
+
+		MM_Wait (40);
+		ptr = (LM_UINT32 *) pBufferVirt;
+		/* Fill data with zero */
+		for (j = 0; j < BufferSize / 4; j++)
+			*ptr++ = 0;
+
+		if (t3_do_dma (pDevice, BufferPhy, BufferSize, 0) ==
+		    LM_STATUS_FAILURE) {
+			return LM_STATUS_FAILURE;
+		}
+
+		MM_Wait (40);
+		/* Check for data */
+		ptr = (LM_UINT32 *) pBufferVirt;
+		for (j = 0; j < BufferSize / 4; j++) {
+			if (*ptr++ != j) {
+				if ((pDevice->
+				     DmaReadWriteCtrl &
+				     DMA_CTRL_WRITE_BOUNDARY_MASK)
+				    == DMA_CTRL_WRITE_BOUNDARY_DISABLE) {
+					pDevice->DmaReadWriteCtrl =
+					    (pDevice->
+					     DmaReadWriteCtrl &
+					     ~DMA_CTRL_WRITE_BOUNDARY_MASK) |
+					    DMA_CTRL_WRITE_BOUNDARY_16;
+					REG_WR (pDevice,
+						PciCfg.DmaReadWriteCtrl,
+						pDevice->DmaReadWriteCtrl);
+					break;
+				} else {
+					return LM_STATUS_FAILURE;
+				}
+			}
+		}
+		if (j == (BufferSize / 4))
+			dma_success = 1;
+	}
+	return LM_STATUS_SUCCESS;
+}
+
+#endif
diff --git a/drivers/net/tigon3.h b/drivers/net/tigon3.h
new file mode 100644
index 0000000..c03347f
--- /dev/null
+++ b/drivers/net/tigon3.h
@@ -0,0 +1,3339 @@
+
+/******************************************************************************/
+/*                                                                            */
+/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
+/* Corporation.                                                               */
+/* All rights reserved.                                                       */
+/*                                                                            */
+/* 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, located in the file LICENSE.                 */
+/*                                                                            */
+/* History:                                                                   */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef TIGON3_H
+#define TIGON3_H
+
+#include "bcm570x_lm.h"
+#if INCLUDE_TBI_SUPPORT
+#include "bcm570x_autoneg.h"
+#endif
+
+/* io defines */
+#if !defined(BIG_ENDIAN_HOST)
+#define readl(addr) \
+	      (LONGSWAP((*(volatile unsigned int *)(addr))))
+#define writel(b,addr) \
+	      ((*(volatile unsigned int *)(addr)) = (LONGSWAP(b)))
+#else
+#if 0				/* !defined(PPC603) */
+#define readl(addr) (*(volatile unsigned int*)(0xa0000000 + (unsigned long)(addr)))
+#define writel(b,addr) ((*(volatile unsigned int *) ((unsigned long)(addr) + 0xa0000000)) = (b))
+#else
+#if 1
+#define readl(addr) (*(volatile unsigned int*)(addr))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+#else
+extern int sprintf (char *buf, const char *f, ...);
+static __inline unsigned int readl (void *addr)
+{
+	char buf[128];
+	unsigned int tmp = (*(volatile unsigned int *)(addr));
+	sprintf (buf, "%s:%s: read 0x%x from 0x%x\n", __FILE__, __LINE__, tmp,
+		 addr, 0, 0);
+	sysSerialPrintString (buf);
+	return tmp;
+}
+static __inline void writel (unsigned int b, unsigned int addr)
+{
+	char buf[128];
+	((*(volatile unsigned int *)(addr)) = (b));
+	sprintf (buf, "%s:%s: write 0x%x to 0x%x\n", __FILE__, __LINE__, b,
+		 addr, 0, 0);
+	sysSerialPrintString (buf);
+}
+#endif
+#endif				/* PPC603 */
+#endif
+
+/******************************************************************************/
+/* Constants. */
+/******************************************************************************/
+
+/* Maxim number of packet descriptors used for sending packets. */
+#define MAX_TX_PACKET_DESC_COUNT            600
+#define DEFAULT_TX_PACKET_DESC_COUNT        2
+
+/* Maximum number of packet descriptors used for receiving packets. */
+#if T3_JUMBO_RCB_ENTRY_COUNT
+#define MAX_RX_PACKET_DESC_COUNT                                            \
+    (T3_STD_RCV_RCB_ENTRY_COUNT + T3_JUMBO_RCV_RCB_ENTRY_COUNT)
+#else
+#define MAX_RX_PACKET_DESC_COUNT            800
+#endif
+#define DEFAULT_RX_PACKET_DESC_COUNT        2
+
+/* Threshhold for double copying small tx packets.  0 will disable double */
+/* copying of small Tx packets. */
+#define DEFAULT_TX_COPY_BUFFER_SIZE         0
+#define MIN_TX_COPY_BUFFER_SIZE             64
+#define MAX_TX_COPY_BUFFER_SIZE             512
+
+/* Cache line. */
+#define COMMON_CACHE_LINE_SIZE              0x20
+#define COMMON_CACHE_LINE_MASK              (COMMON_CACHE_LINE_SIZE-1)
+
+/* Maximum number of fragment we can handle. */
+#ifndef MAX_FRAGMENT_COUNT
+#define MAX_FRAGMENT_COUNT                  32
+#endif
+
+/* B0 bug. */
+#define BCM5700_BX_MIN_FRAG_SIZE            10
+#define BCM5700_BX_MIN_FRAG_BUF_SIZE        16	/* nice aligned size. */
+#define BCM5700_BX_MIN_FRAG_BUF_SIZE_MASK   (BCM5700_BX_MIN_FRAG_BUF_SIZE-1)
+#define BCM5700_BX_TX_COPY_BUF_SIZE         (BCM5700_BX_MIN_FRAG_BUF_SIZE * \
+					    MAX_FRAGMENT_COUNT)
+
+/* MAGIC number. */
+/* #define T3_MAGIC_NUM                        'KevT' */
+#define T3_FIRMWARE_MAILBOX                0x0b50
+#define T3_MAGIC_NUM                       0x4B657654
+#define T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE 0x4861764b
+
+#define T3_NIC_DATA_SIG_ADDR               0x0b54
+#define T3_NIC_DATA_SIG                    0x4b657654
+
+#define T3_NIC_DATA_NIC_CFG_ADDR           0x0b58
+#define T3_NIC_CFG_LED_MODE_UNKNOWN        BIT_NONE
+#define T3_NIC_CFG_LED_MODE_TRIPLE_SPEED   BIT_2
+#define T3_NIC_CFG_LED_MODE_LINK_SPEED     BIT_3
+#define T3_NIC_CFG_LED_MODE_OPEN_DRAIN     BIT_2
+#define T3_NIC_CFG_LED_MODE_OUTPUT         BIT_3
+#define T3_NIC_CFG_LED_MODE_MASK           (BIT_2 | BIT_3)
+#define T3_NIC_CFG_PHY_TYPE_UNKNOWN         BIT_NONE
+#define T3_NIC_CFG_PHY_TYPE_COPPER          BIT_4
+#define T3_NIC_CFG_PHY_TYPE_FIBER           BIT_5
+#define T3_NIC_CFG_PHY_TYPE_MASK            (BIT_4 | BIT_5)
+#define T3_NIC_CFG_ENABLE_WOL               BIT_6
+#define T3_NIC_CFG_ENABLE_ASF               BIT_7
+#define T3_NIC_EEPROM_WP                    BIT_8
+
+#define T3_NIC_DATA_PHY_ID_ADDR            0x0b74
+#define T3_NIC_PHY_ID1_MASK                0xffff0000
+#define T3_NIC_PHY_ID2_MASK                0x0000ffff
+
+#define T3_CMD_MAILBOX                      0x0b78
+#define T3_CMD_NICDRV_ALIVE                 0x01
+#define T3_CMD_NICDRV_PAUSE_FW              0x02
+#define T3_CMD_NICDRV_IPV4ADDR_CHANGE       0x03
+#define T3_CMD_NICDRV_IPV6ADDR_CHANGE       0x04
+#define T3_CMD_5703A0_FIX_DMAFW_DMAR        0x05
+#define T3_CMD_5703A0_FIX_DMAFW_DMAW        0x06
+
+#define T3_CMD_LENGTH_MAILBOX               0x0b7c
+#define T3_CMD_DATA_MAILBOX                 0x0b80
+
+#define T3_ASF_FW_STATUS_MAILBOX            0x0c00
+
+#define T3_DRV_STATE_MAILBOX                0x0c04
+#define T3_DRV_STATE_START                  0x01
+#define T3_DRV_STATE_UNLOAD                 0x02
+#define T3_DRV_STATE_WOL                    0x03
+#define T3_DRV_STATE_SUSPEND                0x04
+
+#define T3_FW_RESET_TYPE_MAILBOX            0x0c08
+
+#define T3_MAC_ADDR_HIGH_MAILBOX            0x0c14
+#define T3_MAC_ADDR_LOW_MAILBOX             0x0c18
+
+/******************************************************************************/
+/* Hardware constants. */
+/******************************************************************************/
+
+/* Number of entries in the send ring:  must be 512. */
+#define T3_SEND_RCB_ENTRY_COUNT             512
+#define T3_SEND_RCB_ENTRY_COUNT_MASK        (T3_SEND_RCB_ENTRY_COUNT-1)
+
+/* Number of send RCBs.  May be 1-16 but for now, only support one. */
+#define T3_MAX_SEND_RCB_COUNT               16
+
+/* Number of entries in the Standard Receive RCB.  Must be 512 entries. */
+#define T3_STD_RCV_RCB_ENTRY_COUNT          512
+#define T3_STD_RCV_RCB_ENTRY_COUNT_MASK     (T3_STD_RCV_RCB_ENTRY_COUNT-1)
+#define DEFAULT_STD_RCV_DESC_COUNT          200	/* Must be < 512. */
+#define MAX_STD_RCV_BUFFER_SIZE             0x600
+
+/* Number of entries in the Mini Receive RCB.  This value can either be */
+/* 0, 1024.  Currently Mini Receive RCB is disabled. */
+#ifndef T3_MINI_RCV_RCB_ENTRY_COUNT
+#define T3_MINI_RCV_RCB_ENTRY_COUNT         0
+#endif				/* T3_MINI_RCV_RCB_ENTRY_COUNT */
+#define T3_MINI_RCV_RCB_ENTRY_COUNT_MASK    (T3_MINI_RCV_RCB_ENTRY_COUNT-1)
+#define MAX_MINI_RCV_BUFFER_SIZE            512
+#define DEFAULT_MINI_RCV_BUFFER_SIZE        64
+#define DEFAULT_MINI_RCV_DESC_COUNT         100	/* Must be < 1024. */
+
+/* Number of entries in the Jumbo Receive RCB.  This value must 256 or 0. */
+/* Currently, Jumbo Receive RCB is disabled. */
+#ifndef T3_JUMBO_RCV_RCB_ENTRY_COUNT
+#define T3_JUMBO_RCV_RCB_ENTRY_COUNT        0
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+#define T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK   (T3_JUMBO_RCV_RCB_ENTRY_COUNT-1)
+
+#define MAX_JUMBO_RCV_BUFFER_SIZE           (10 * 1024)	/* > 1514 */
+#define DEFAULT_JUMBO_RCV_BUFFER_SIZE       (4 * 1024)	/* > 1514 */
+#define DEFAULT_JUMBO_RCV_DESC_COUNT        128	/* Must be < 256. */
+
+#define MAX_JUMBO_TX_BUFFER_SIZE            (8 * 1024)	/* > 1514 */
+#define DEFAULT_JUMBO_TX_BUFFER_SIZE        (4 * 1024)	/* > 1514 */
+
+/* Number of receive return RCBs.  Maybe 1-16 but for now, only support one. */
+#define T3_MAX_RCV_RETURN_RCB_COUNT         16
+
+/* Number of entries in a Receive Return ring.  This value is either 1024 */
+/* or 2048. */
+#ifndef T3_RCV_RETURN_RCB_ENTRY_COUNT
+#define T3_RCV_RETURN_RCB_ENTRY_COUNT       1024
+#endif				/* T3_RCV_RETURN_RCB_ENTRY_COUNT */
+#define T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK  (T3_RCV_RETURN_RCB_ENTRY_COUNT-1)
+
+/* Default coalescing parameters. */
+#define DEFAULT_RX_COALESCING_TICKS         100
+#define MAX_RX_COALESCING_TICKS             500
+#define DEFAULT_TX_COALESCING_TICKS         400
+#define MAX_TX_COALESCING_TICKS             500
+#define DEFAULT_RX_MAX_COALESCED_FRAMES     10
+#define MAX_RX_MAX_COALESCED_FRAMES         100
+#define ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES    5
+#define ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES    42
+#define ADAPTIVE_LO_RX_COALESCING_TICKS         50
+#define ADAPTIVE_HI_RX_COALESCING_TICKS         300
+#define ADAPTIVE_LO_PKT_THRESH              30000
+#define ADAPTIVE_HI_PKT_THRESH              74000
+#define DEFAULT_TX_MAX_COALESCED_FRAMES     40
+#define ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES    25
+#define ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES    75
+#define MAX_TX_MAX_COALESCED_FRAMES         100
+
+#define DEFAULT_RX_COALESCING_TICKS_DURING_INT          25
+#define DEFAULT_TX_COALESCING_TICKS_DURING_INT          25
+#define DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT      5
+#define DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT      5
+
+#define BAD_DEFAULT_VALUE                               0xffffffff
+
+#define DEFAULT_STATS_COALESCING_TICKS      1000000
+#define MAX_STATS_COALESCING_TICKS          3600000000U
+
+/* Receive BD Replenish thresholds. */
+#define DEFAULT_RCV_STD_BD_REPLENISH_THRESHOLD      4
+#define DEFAULT_RCV_JUMBO_BD_REPLENISH_THRESHOLD    4
+
+#define SPLIT_MODE_DISABLE                          0
+#define SPLIT_MODE_ENABLE                           1
+
+#define SPLIT_MODE_5704_MAX_REQ                     3
+
+/* Maximum physical fragment size. */
+#define MAX_FRAGMENT_SIZE                   (64 * 1024)
+
+/* Standard view. */
+#define T3_STD_VIEW_SIZE                    (64 * 1024)
+#define T3_FLAT_VIEW_SIZE                   (32 * 1024 * 1024)
+
+/* Buffer descriptor base address on the NIC's memory. */
+
+#define T3_NIC_SND_BUFFER_DESC_ADDR         0x4000
+#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR     0x6000
+#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR   0x7000
+
+#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR_EXT_MEM     0xc000
+#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR_EXT_MEM   0xd000
+#define T3_NIC_MINI_RCV_BUFFER_DESC_ADDR_EXT_MEM    0xe000
+
+#define T3_NIC_SND_BUFFER_DESC_SIZE         (T3_SEND_RCB_ENTRY_COUNT * \
+					    sizeof(T3_SND_BD) / 4)
+
+#define T3_NIC_STD_RCV_BUFFER_DESC_SIZE     (T3_STD_RCV_RCB_ENTRY_COUNT * \
+					    sizeof(T3_RCV_BD) / 4)
+
+#define T3_NIC_JUMBO_RCV_BUFFER_DESC_SIZE   (T3_JUMBO_RCV_RCB_ENTRY_COUNT * \
+					    sizeof(T3_EXT_RCV_BD) / 4)
+
+/* MBUF pool. */
+#define T3_NIC_MBUF_POOL_ADDR               0x8000
+/* #define T3_NIC_MBUF_POOL_SIZE               0x18000 */
+#define T3_NIC_MBUF_POOL_SIZE96             0x18000
+#define T3_NIC_MBUF_POOL_SIZE64             0x10000
+
+#define T3_NIC_MBUF_POOL_ADDR_EXT_MEM       0x20000
+
+/* DMA descriptor pool */
+#define T3_NIC_DMA_DESC_POOL_ADDR           0x2000
+#define T3_NIC_DMA_DESC_POOL_SIZE           0x2000	/* 8KB. */
+
+#define T3_DEF_DMA_MBUF_LOW_WMARK           0x40
+#define T3_DEF_RX_MAC_MBUF_LOW_WMARK        0x20
+#define T3_DEF_MBUF_HIGH_WMARK              0x60
+
+#define T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO     304
+#define T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO  152
+#define T3_DEF_MBUF_HIGH_WMARK_JUMBO        380
+
+#define T3_DEF_DMA_DESC_LOW_WMARK           5
+#define T3_DEF_DMA_DESC_HIGH_WMARK          10
+
+/* Maximum size of giant TCP packet can be sent */
+#define T3_TCP_SEG_MAX_OFFLOAD_SIZE         64*1000
+#define T3_TCP_SEG_MIN_NUM_SEG              20
+
+#define T3_RX_CPU_ID    0x1
+#define T3_TX_CPU_ID    0x2
+#define T3_RX_CPU_SPAD_ADDR  0x30000
+#define T3_RX_CPU_SPAD_SIZE  0x4000
+#define T3_TX_CPU_SPAD_ADDR  0x34000
+#define T3_TX_CPU_SPAD_SIZE  0x4000
+
+typedef struct T3_DIR_ENTRY {
+	PLM_UINT8 Buffer;
+	LM_UINT32 Offset;
+	LM_UINT32 Length;
+} T3_DIR_ENTRY, *PT3_DIR_ENTRY;
+
+typedef struct T3_FWIMG_INFO {
+	LM_UINT32 StartAddress;
+	T3_DIR_ENTRY Text;
+	T3_DIR_ENTRY ROnlyData;
+	T3_DIR_ENTRY Data;
+	T3_DIR_ENTRY Sbss;
+	T3_DIR_ENTRY Bss;
+} T3_FWIMG_INFO, *PT3_FWIMG_INFO;
+
+/******************************************************************************/
+/* Tigon3 PCI Registers. */
+/******************************************************************************/
+#define T3_PCI_ID_BCM5700                   0x164414e4
+#define T3_PCI_ID_BCM5701                   0x164514e4
+#define T3_PCI_ID_BCM5702                   0x164614e4
+#define T3_PCI_ID_BCM5702x                  0x16A614e4
+#define T3_PCI_ID_BCM5703                   0x164714e4
+#define T3_PCI_ID_BCM5703x                  0x16A714e4
+#define T3_PCI_ID_BCM5702FE                 0x164D14e4
+#define T3_PCI_ID_BCM5704                   0x164814e4
+
+#define T3_PCI_VENDOR_ID                    (T3_PCI_ID & 0xffff)
+#define T3_PCI_DEVICE_ID                    (T3_PCI_ID >> 16)
+
+#define T3_PCI_MISC_HOST_CTRL_REG           0x68
+
+/* The most significant 16bit of register 0x68. */
+/* ChipId:4, ChipRev:4, MetalRev:8 */
+#define T3_CHIP_ID_5700_A0                  0x7000
+#define T3_CHIP_ID_5700_A1                  0x7001
+#define T3_CHIP_ID_5700_B0                  0x7100
+#define T3_CHIP_ID_5700_B1                  0x7101
+#define T3_CHIP_ID_5700_C0                  0x7200
+
+#define T3_CHIP_ID_5701_A0                  0x0000
+#define T3_CHIP_ID_5701_B0                  0x0100
+#define T3_CHIP_ID_5701_B2                  0x0102
+#define T3_CHIP_ID_5701_B5                  0x0105
+
+#define T3_CHIP_ID_5703_A0                  0x1000
+#define T3_CHIP_ID_5703_A1                  0x1001
+#define T3_CHIP_ID_5703_A2                  0x1002
+
+#define T3_CHIP_ID_5704_A0                  0x2000
+
+/* Chip Id. */
+#define T3_ASIC_REV(_ChipRevId)             ((_ChipRevId) >> 12)
+#define T3_ASIC_REV_5700                    0x07
+#define T3_ASIC_REV_5701                    0x00
+#define T3_ASIC_REV_5703                    0x01
+#define T3_ASIC_REV_5704                    0x02
+
+/* Chip id and revision. */
+#define T3_CHIP_REV(_ChipRevId)             ((_ChipRevId) >> 8)
+#define T3_CHIP_REV_5700_AX                 0x70
+#define T3_CHIP_REV_5700_BX                 0x71
+#define T3_CHIP_REV_5700_CX                 0x72
+#define T3_CHIP_REV_5701_AX                 0x00
+
+/* Metal revision. */
+#define T3_METAL_REV(_ChipRevId)            ((_ChipRevId) & 0xff)
+#define T3_METAL_REV_A0                     0x00
+#define T3_METAL_REV_A1                     0x01
+#define T3_METAL_REV_B0                     0x00
+#define T3_METAL_REV_B1                     0x01
+#define T3_METAL_REV_B2                     0x02
+
+#define T3_PCI_REG_CLOCK_CTRL               0x74
+
+#define T3_PCI_DISABLE_RX_CLOCK             BIT_10
+#define T3_PCI_DISABLE_TX_CLOCK             BIT_11
+#define T3_PCI_SELECT_ALTERNATE_CLOCK       BIT_12
+#define T3_PCI_POWER_DOWN_PCI_PLL133        BIT_15
+#define T3_PCI_44MHZ_CORE_CLOCK             BIT_18
+
+#define T3_PCI_REG_ADDR_REG                 0x78
+#define T3_PCI_REG_DATA_REG                 0x80
+
+#define T3_PCI_MEM_WIN_ADDR_REG             0x7c
+#define T3_PCI_MEM_WIN_DATA_REG             0x84
+
+#define T3_PCI_PM_CAP_REG                   0x48
+
+#define T3_PCI_PM_CAP_PME_D3COLD            BIT_31
+#define T3_PCI_PM_CAP_PME_D3HOT             BIT_30
+
+#define T3_PCI_PM_STATUS_CTRL_REG           0x4c
+
+#define T3_PM_POWER_STATE_MASK              (BIT_0 | BIT_1)
+#define T3_PM_POWER_STATE_D0                BIT_NONE
+#define T3_PM_POWER_STATE_D1                BIT_0
+#define T3_PM_POWER_STATE_D2                BIT_1
+#define T3_PM_POWER_STATE_D3                (BIT_0 | BIT_1)
+
+#define T3_PM_PME_ENABLE                    BIT_8
+#define T3_PM_PME_ASSERTED                  BIT_15
+
+/* PCI state register. */
+#define T3_PCI_STATE_REG                    0x70
+
+#define T3_PCI_STATE_FORCE_RESET            BIT_0
+#define T3_PCI_STATE_INT_NOT_ACTIVE         BIT_1
+#define T3_PCI_STATE_CONVENTIONAL_PCI_MODE  BIT_2
+#define T3_PCI_STATE_BUS_SPEED_HIGH         BIT_3
+#define T3_PCI_STATE_32BIT_PCI_BUS          BIT_4
+
+/* Broadcom subsystem/subvendor IDs. */
+#define T3_SVID_BROADCOM                            0x14e4
+
+#define T3_SSID_BROADCOM_BCM95700A6                 0x1644
+#define T3_SSID_BROADCOM_BCM95701A5                 0x0001
+#define T3_SSID_BROADCOM_BCM95700T6                 0x0002	/* BCM8002 */
+#define T3_SSID_BROADCOM_BCM95700A9                 0x0003	/* Agilent */
+#define T3_SSID_BROADCOM_BCM95701T1                 0x0005
+#define T3_SSID_BROADCOM_BCM95701T8                 0x0006
+#define T3_SSID_BROADCOM_BCM95701A7                 0x0007	/* Agilent */
+#define T3_SSID_BROADCOM_BCM95701A10                0x0008
+#define T3_SSID_BROADCOM_BCM95701A12                0x8008
+#define T3_SSID_BROADCOM_BCM95703Ax1                0x0009
+#define T3_SSID_BROADCOM_BCM95703Ax2                0x8009
+
+/* 3COM subsystem/subvendor IDs. */
+#define T3_SVID_3COM                                0x10b7
+
+#define T3_SSID_3COM_3C996T                         0x1000
+#define T3_SSID_3COM_3C996BT                        0x1006
+#define T3_SSID_3COM_3C996CT                        0x1002
+#define T3_SSID_3COM_3C997T                         0x1003
+#define T3_SSID_3COM_3C1000T                        0x1007
+#define T3_SSID_3COM_3C940BR01                      0x1008
+
+/* Fiber boards. */
+#define T3_SSID_3COM_3C996SX                        0x1004
+#define T3_SSID_3COM_3C997SX                        0x1005
+
+/* Dell subsystem/subvendor IDs. */
+
+#define T3_SVID_DELL                                0x1028
+
+#define T3_SSID_DELL_VIPER                          0x00d1
+#define T3_SSID_DELL_JAGUAR                         0x0106
+#define T3_SSID_DELL_MERLOT                         0x0109
+#define T3_SSID_DELL_SLIM_MERLOT                    0x010a
+
+/* Compaq subsystem/subvendor IDs */
+
+#define T3_SVID_COMPAQ                              0x0e11
+
+#define T3_SSID_COMPAQ_BANSHEE                      0x007c
+#define T3_SSID_COMPAQ_BANSHEE_2                    0x009a
+#define T3_SSID_COMPAQ_CHANGELING                   0x007d
+#define T3_SSID_COMPAQ_NC7780                       0x0085
+#define T3_SSID_COMPAQ_NC7780_2                     0x0099
+
+/******************************************************************************/
+/* MII registers. */
+/******************************************************************************/
+
+/* Control register. */
+#define PHY_CTRL_REG                                0x00
+
+#define PHY_CTRL_SPEED_MASK                         (BIT_6 | BIT_13)
+#define PHY_CTRL_SPEED_SELECT_10MBPS                BIT_NONE
+#define PHY_CTRL_SPEED_SELECT_100MBPS               BIT_13
+#define PHY_CTRL_SPEED_SELECT_1000MBPS              BIT_6
+#define PHY_CTRL_COLLISION_TEST_ENABLE              BIT_7
+#define PHY_CTRL_FULL_DUPLEX_MODE                   BIT_8
+#define PHY_CTRL_RESTART_AUTO_NEG                   BIT_9
+#define PHY_CTRL_ISOLATE_PHY                        BIT_10
+#define PHY_CTRL_LOWER_POWER_MODE                   BIT_11
+#define PHY_CTRL_AUTO_NEG_ENABLE                    BIT_12
+#define PHY_CTRL_LOOPBACK_MODE                      BIT_14
+#define PHY_CTRL_PHY_RESET                          BIT_15
+
+/* Status register. */
+#define PHY_STATUS_REG                              0x01
+
+#define PHY_STATUS_LINK_PASS                        BIT_2
+#define PHY_STATUS_AUTO_NEG_COMPLETE                BIT_5
+
+/* Phy Id registers. */
+#define PHY_ID1_REG                                 0x02
+#define PHY_ID1_OUI_MASK                            0xffff
+
+#define PHY_ID2_REG                                 0x03
+#define PHY_ID2_REV_MASK                            0x000f
+#define PHY_ID2_MODEL_MASK                          0x03f0
+#define PHY_ID2_OUI_MASK                            0xfc00
+
+/* Auto-negotiation advertisement register. */
+#define PHY_AN_AD_REG                               0x04
+
+#define PHY_AN_AD_ASYM_PAUSE                        BIT_11
+#define PHY_AN_AD_PAUSE_CAPABLE                     BIT_10
+#define PHY_AN_AD_10BASET_HALF                      BIT_5
+#define PHY_AN_AD_10BASET_FULL                      BIT_6
+#define PHY_AN_AD_100BASETX_HALF                    BIT_7
+#define PHY_AN_AD_100BASETX_FULL                    BIT_8
+#define PHY_AN_AD_PROTOCOL_802_3_CSMA_CD            0x01
+
+/* Auto-negotiation Link Partner Ability register. */
+#define PHY_LINK_PARTNER_ABILITY_REG                0x05
+
+#define PHY_LINK_PARTNER_ASYM_PAUSE                 BIT_11
+#define PHY_LINK_PARTNER_PAUSE_CAPABLE              BIT_10
+
+/* Auto-negotiation expansion register. */
+#define PHY_AN_EXPANSION_REG                        0x06
+
+/******************************************************************************/
+/* BCM5400 and BCM5401 phy info. */
+/******************************************************************************/
+
+#define PHY_DEVICE_ID           1
+
+/* OUI: bit 31-10;   Model#: bit 9-4;   Rev# bit 3-0. */
+#define PHY_UNKNOWN_PHY                             0x00000000
+#define PHY_BCM5400_PHY_ID                          0x60008040
+#define PHY_BCM5401_PHY_ID                          0x60008050
+#define PHY_BCM5411_PHY_ID                          0x60008070
+#define PHY_BCM5701_PHY_ID                          0x60008110
+#define PHY_BCM5703_PHY_ID                          0x60008160
+#define PHY_BCM5704_PHY_ID                          0x60008190
+#define PHY_BCM8002_PHY_ID                          0x60010140
+
+#define PHY_BCM5401_B0_REV                          0x1
+#define PHY_BCM5401_B2_REV                          0x3
+#define PHY_BCM5401_C0_REV                          0x6
+
+#define PHY_ID_OUI_MASK                             0xfffffc00
+#define PHY_ID_MODEL_MASK                           0x000003f0
+#define PHY_ID_REV_MASK                             0x0000000f
+#define PHY_ID_MASK                                 (PHY_ID_OUI_MASK |      \
+						    PHY_ID_MODEL_MASK)
+
+#define UNKNOWN_PHY_ID(x)   ((((x) & PHY_ID_MASK) != PHY_BCM5400_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM5401_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM5411_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM5701_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM5703_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM5704_PHY_ID) && \
+			    (((x) & PHY_ID_MASK) != PHY_BCM8002_PHY_ID))
+
+/* 1000Base-T control register. */
+#define BCM540X_1000BASET_CTRL_REG                  0x09
+
+#define BCM540X_AN_AD_1000BASET_HALF                BIT_8
+#define BCM540X_AN_AD_1000BASET_FULL                BIT_9
+#define BCM540X_CONFIG_AS_MASTER                    BIT_11
+#define BCM540X_ENABLE_CONFIG_AS_MASTER             BIT_12
+
+/* Extended control register. */
+#define BCM540X_EXT_CTRL_REG                        0x10
+
+#define BCM540X_EXT_CTRL_LINK3_LED_MODE             BIT_1
+#define BCM540X_EXT_CTRL_TBI                        BIT_15
+
+/* PHY extended status register. */
+#define BCM540X_EXT_STATUS_REG                      0x11
+
+#define BCM540X_EXT_STATUS_LINK_PASS                BIT_8
+
+/* DSP Coefficient Read/Write Port. */
+#define BCM540X_DSP_RW_PORT                         0x15
+
+/* DSP Coeficient Address Register. */
+#define BCM540X_DSP_ADDRESS_REG                     0x17
+
+#define BCM540X_DSP_TAP_NUMBER_MASK                 0x00
+#define BCM540X_DSP_AGC_A                           0x00
+#define BCM540X_DSP_AGC_B                           0x01
+#define BCM540X_DSP_MSE_PAIR_STATUS                 0x02
+#define BCM540X_DSP_SOFT_DECISION                   0x03
+#define BCM540X_DSP_PHASE_REG                       0x04
+#define BCM540X_DSP_SKEW                            0x05
+#define BCM540X_DSP_POWER_SAVER_UPPER_BOUND         0x06
+#define BCM540X_DSP_POWER_SAVER_LOWER_BOUND         0x07
+#define BCM540X_DSP_LAST_ECHO                       0x08
+#define BCM540X_DSP_FREQUENCY                       0x09
+#define BCM540X_DSP_PLL_BANDWIDTH                   0x0a
+#define BCM540X_DSP_PLL_PHASE_OFFSET                0x0b
+
+#define BCM540X_DSP_FILTER_DCOFFSET                 (BIT_10 | BIT_11)
+#define BCM540X_DSP_FILTER_FEXT3                    (BIT_8 | BIT_9 | BIT_11)
+#define BCM540X_DSP_FILTER_FEXT2                    (BIT_9 | BIT_11)
+#define BCM540X_DSP_FILTER_FEXT1                    (BIT_8 | BIT_11)
+#define BCM540X_DSP_FILTER_FEXT0                    BIT_11
+#define BCM540X_DSP_FILTER_NEXT3                    (BIT_8 | BIT_9 | BIT_10)
+#define BCM540X_DSP_FILTER_NEXT2                    (BIT_9 | BIT_10)
+#define BCM540X_DSP_FILTER_NEXT1                    (BIT_8 | BIT_10)
+#define BCM540X_DSP_FILTER_NEXT0                    BIT_10
+#define BCM540X_DSP_FILTER_ECHO                     (BIT_8 | BIT_9)
+#define BCM540X_DSP_FILTER_DFE                      BIT_9
+#define BCM540X_DSP_FILTER_FFE                      BIT_8
+
+#define BCM540X_DSP_CONTROL_ALL_FILTERS             BIT_12
+
+#define BCM540X_DSP_SEL_CH_0                        BIT_NONE
+#define BCM540X_DSP_SEL_CH_1                        BIT_13
+#define BCM540X_DSP_SEL_CH_2                        BIT_14
+#define BCM540X_DSP_SEL_CH_3                        (BIT_13 | BIT_14)
+
+#define BCM540X_CONTROL_ALL_CHANNELS                BIT_15
+
+/* Auxilliary Control Register (Shadow Register) */
+#define BCM5401_AUX_CTRL                            0x18
+
+#define BCM5401_SHADOW_SEL_MASK                     0x7
+#define BCM5401_SHADOW_SEL_NORMAL                   0x00
+#define BCM5401_SHADOW_SEL_10BASET                  0x01
+#define BCM5401_SHADOW_SEL_POWER_CONTROL            0x02
+#define BCM5401_SHADOW_SEL_IP_PHONE                 0x03
+#define BCM5401_SHADOW_SEL_MISC_TEST1               0x04
+#define BCM5401_SHADOW_SEL_MISC_TEST2               0x05
+#define BCM5401_SHADOW_SEL_IP_PHONE_SEED            0x06
+
+/* Shadow register selector == '000' */
+#define BCM5401_SHDW_NORMAL_DIAG_MODE               BIT_3
+#define BCM5401_SHDW_NORMAL_DISABLE_MBP             BIT_4
+#define BCM5401_SHDW_NORMAL_DISABLE_LOW_PWR         BIT_5
+#define BCM5401_SHDW_NORMAL_DISABLE_INV_PRF         BIT_6
+#define BCM5401_SHDW_NORMAL_DISABLE_PRF             BIT_7
+#define BCM5401_SHDW_NORMAL_RX_SLICING_NORMAL       BIT_NONE
+#define BCM5401_SHDW_NORMAL_RX_SLICING_4D           BIT_8
+#define BCM5401_SHDW_NORMAL_RX_SLICING_3LVL_1D      BIT_9
+#define BCM5401_SHDW_NORMAL_RX_SLICING_5LVL_1D      (BIT_8 | BIT_9)
+#define BCM5401_SHDW_NORMAL_TX_6DB_CODING           BIT_10
+#define BCM5401_SHDW_NORMAL_ENABLE_SM_DSP_CLOCK     BIT_11
+#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_4NS       BIT_NONE
+#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_5NS       BIT_12
+#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_3NS       BIT_13
+#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_0NS       (BIT_12 | BIT_13)
+#define BCM5401_SHDW_NORMAL_EXT_PACKET_LENGTH       BIT_14
+#define BCM5401_SHDW_NORMAL_EXTERNAL_LOOPBACK       BIT_15
+
+/* Auxilliary status summary. */
+#define BCM540X_AUX_STATUS_REG                      0x19
+
+#define BCM540X_AUX_LINK_PASS                       BIT_2
+#define BCM540X_AUX_SPEED_MASK                      (BIT_8 | BIT_9 | BIT_10)
+#define BCM540X_AUX_10BASET_HD                      BIT_8
+#define BCM540X_AUX_10BASET_FD                      BIT_9
+#define BCM540X_AUX_100BASETX_HD                    (BIT_8 | BIT_9)
+#define BCM540X_AUX_100BASET4                       BIT_10
+#define BCM540X_AUX_100BASETX_FD                    (BIT_8 | BIT_10)
+#define BCM540X_AUX_100BASET_HD                     (BIT_9 | BIT_10)
+#define BCM540X_AUX_100BASET_FD                     (BIT_8 | BIT_9 | BIT_10)
+
+/* Interrupt status. */
+#define BCM540X_INT_STATUS_REG                      0x1a
+
+#define BCM540X_INT_LINK_CHANGE                     BIT_1
+#define BCM540X_INT_SPEED_CHANGE                    BIT_2
+#define BCM540X_INT_DUPLEX_CHANGE                   BIT_3
+#define BCM540X_INT_AUTO_NEG_PAGE_RX                BIT_10
+
+/* Interrupt mask register. */
+#define BCM540X_INT_MASK_REG                        0x1b
+
+/******************************************************************************/
+/* Register definitions. */
+/******************************************************************************/
+
+typedef volatile LM_UINT8 T3_8BIT_REGISTER, *PT3_8BIT_REGISTER;
+typedef volatile LM_UINT16 T3_16BIT_REGISTER, *PT3_16BIT_REGISTER;
+typedef volatile LM_UINT32 T3_32BIT_REGISTER, *PT3_32BIT_REGISTER;
+
+typedef struct {
+	/* Big endian format. */
+	T3_32BIT_REGISTER High;
+	T3_32BIT_REGISTER Low;
+} T3_64BIT_REGISTER, *PT3_64BIT_REGISTER;
+
+typedef T3_64BIT_REGISTER T3_64BIT_HOST_ADDR, *PT3_64BIT_HOST_ADDR;
+
+#define T3_NUM_OF_DMA_DESC    256
+#define T3_NUM_OF_MBUF        768
+
+typedef struct {
+	T3_64BIT_REGISTER host_addr;
+	T3_32BIT_REGISTER nic_mbuf;
+	T3_16BIT_REGISTER len;
+	T3_16BIT_REGISTER cqid_sqid;
+	T3_32BIT_REGISTER flags;
+	T3_32BIT_REGISTER opaque1;
+	T3_32BIT_REGISTER opaque2;
+	T3_32BIT_REGISTER opaque3;
+} T3_DMA_DESC, *PT3_DMA_DESC;
+
+/******************************************************************************/
+/* Ring control block. */
+/******************************************************************************/
+
+typedef struct {
+	T3_64BIT_REGISTER HostRingAddr;
+
+	union {
+		struct {
+#ifdef BIG_ENDIAN_HOST
+			T3_16BIT_REGISTER MaxLen;
+			T3_16BIT_REGISTER Flags;
+#else				/* BIG_ENDIAN_HOST */
+			T3_16BIT_REGISTER Flags;
+			T3_16BIT_REGISTER MaxLen;
+#endif
+		} s;
+
+		T3_32BIT_REGISTER MaxLen_Flags;
+	} u;
+
+	T3_32BIT_REGISTER NicRingAddr;
+} T3_RCB, *PT3_RCB;
+
+#define T3_RCB_FLAG_USE_EXT_RECV_BD                     BIT_0
+#define T3_RCB_FLAG_RING_DISABLED                       BIT_1
+
+/******************************************************************************/
+/* Status block. */
+/******************************************************************************/
+
+/*
+ * Size of status block is actually 0x50 bytes.  Use 0x80 bytes for
+ * cache line alignment.
+ */
+#define T3_STATUS_BLOCK_SIZE                                    0x80
+
+typedef struct {
+	volatile LM_UINT32 Status;
+#define STATUS_BLOCK_UPDATED                                BIT_0
+#define STATUS_BLOCK_LINK_CHANGED_STATUS                    BIT_1
+#define STATUS_BLOCK_ERROR                                  BIT_2
+
+	volatile LM_UINT32 StatusTag;
+
+#ifdef BIG_ENDIAN_HOST
+	volatile LM_UINT16 RcvStdConIdx;
+	volatile LM_UINT16 RcvJumboConIdx;
+
+	volatile LM_UINT16 Reserved2;
+	volatile LM_UINT16 RcvMiniConIdx;
+
+	struct {
+		volatile LM_UINT16 SendConIdx;	/* Send consumer index. */
+		volatile LM_UINT16 RcvProdIdx;	/* Receive producer index. */
+	} Idx[16];
+#else				/* BIG_ENDIAN_HOST */
+	volatile LM_UINT16 RcvJumboConIdx;
+	volatile LM_UINT16 RcvStdConIdx;
+
+	volatile LM_UINT16 RcvMiniConIdx;
+	volatile LM_UINT16 Reserved2;
+
+	struct {
+		volatile LM_UINT16 RcvProdIdx;	/* Receive producer index. */
+		volatile LM_UINT16 SendConIdx;	/* Send consumer index. */
+	} Idx[16];
+#endif
+} T3_STATUS_BLOCK, *PT3_STATUS_BLOCK;
+
+/******************************************************************************/
+/* Receive buffer descriptors. */
+/******************************************************************************/
+
+typedef struct {
+	T3_64BIT_HOST_ADDR HostAddr;
+
+#ifdef BIG_ENDIAN_HOST
+	volatile LM_UINT16 Index;
+	volatile LM_UINT16 Len;
+
+	volatile LM_UINT16 Type;
+	volatile LM_UINT16 Flags;
+
+	volatile LM_UINT16 IpCksum;
+	volatile LM_UINT16 TcpUdpCksum;
+
+	volatile LM_UINT16 ErrorFlag;
+	volatile LM_UINT16 VlanTag;
+#else				/* BIG_ENDIAN_HOST */
+	volatile LM_UINT16 Len;
+	volatile LM_UINT16 Index;
+
+	volatile LM_UINT16 Flags;
+	volatile LM_UINT16 Type;
+
+	volatile LM_UINT16 TcpUdpCksum;
+	volatile LM_UINT16 IpCksum;
+
+	volatile LM_UINT16 VlanTag;
+	volatile LM_UINT16 ErrorFlag;
+#endif
+
+	volatile LM_UINT32 Reserved;
+	volatile LM_UINT32 Opaque;
+} T3_RCV_BD, *PT3_RCV_BD;
+
+typedef struct {
+	T3_64BIT_HOST_ADDR HostAddr[3];
+
+#ifdef BIG_ENDIAN_HOST
+	LM_UINT16 Len1;
+	LM_UINT16 Len2;
+
+	LM_UINT16 Len3;
+	LM_UINT16 Reserved1;
+#else				/* BIG_ENDIAN_HOST */
+	LM_UINT16 Len2;
+	LM_UINT16 Len1;
+
+	LM_UINT16 Reserved1;
+	LM_UINT16 Len3;
+#endif
+
+	T3_RCV_BD StdRcvBd;
+} T3_EXT_RCV_BD, *PT3_EXT_RCV_BD;
+
+/* Error flags. */
+#define RCV_BD_ERR_BAD_CRC                          0x0001
+#define RCV_BD_ERR_COLL_DETECT                      0x0002
+#define RCV_BD_ERR_LINK_LOST_DURING_PKT             0x0004
+#define RCV_BD_ERR_PHY_DECODE_ERR                   0x0008
+#define RCV_BD_ERR_ODD_NIBBLED_RCVD_MII             0x0010
+#define RCV_BD_ERR_MAC_ABORT                        0x0020
+#define RCV_BD_ERR_LEN_LT_64                        0x0040
+#define RCV_BD_ERR_TRUNC_NO_RESOURCES               0x0080
+#define RCV_BD_ERR_GIANT_FRAME_RCVD                 0x0100
+
+/* Buffer descriptor flags. */
+#define RCV_BD_FLAG_END                             0x0004
+#define RCV_BD_FLAG_JUMBO_RING                      0x0020
+#define RCV_BD_FLAG_VLAN_TAG                        0x0040
+#define RCV_BD_FLAG_FRAME_HAS_ERROR                 0x0400
+#define RCV_BD_FLAG_MINI_RING                       0x0800
+#define RCV_BD_FLAG_IP_CHKSUM_FIELD                 0x1000
+#define RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD            0x2000
+#define RCV_BD_FLAG_TCP_PACKET                      0x4000
+
+/******************************************************************************/
+/* Send buffer descriptor. */
+/******************************************************************************/
+
+typedef struct {
+	T3_64BIT_HOST_ADDR HostAddr;
+
+	union {
+		struct {
+#ifdef BIG_ENDIAN_HOST
+			LM_UINT16 Len;
+			LM_UINT16 Flags;
+#else				/* BIG_ENDIAN_HOST */
+			LM_UINT16 Flags;
+			LM_UINT16 Len;
+#endif
+		} s1;
+
+		LM_UINT32 Len_Flags;
+	} u1;
+
+	union {
+		struct {
+#ifdef BIG_ENDIAN_HOST
+			LM_UINT16 Reserved;
+			LM_UINT16 VlanTag;
+#else				/* BIG_ENDIAN_HOST */
+			LM_UINT16 VlanTag;
+			LM_UINT16 Reserved;
+#endif
+		} s2;
+
+		LM_UINT32 VlanTag;
+	} u2;
+} T3_SND_BD, *PT3_SND_BD;
+
+/* Send buffer descriptor flags. */
+#define SND_BD_FLAG_TCP_UDP_CKSUM                   0x0001
+#define SND_BD_FLAG_IP_CKSUM                        0x0002
+#define SND_BD_FLAG_END                             0x0004
+#define SND_BD_FLAG_IP_FRAG                         0x0008
+#define SND_BD_FLAG_IP_FRAG_END                     0x0010
+#define SND_BD_FLAG_VLAN_TAG                        0x0040
+#define SND_BD_FLAG_COAL_NOW                        0x0080
+#define SND_BD_FLAG_CPU_PRE_DMA                     0x0100
+#define SND_BD_FLAG_CPU_POST_DMA                    0x0200
+#define SND_BD_FLAG_INSERT_SRC_ADDR                 0x1000
+#define SND_BD_FLAG_CHOOSE_SRC_ADDR                 0x6000
+#define SND_BD_FLAG_DONT_GEN_CRC                    0x8000
+
+/* MBUFs */
+typedef struct T3_MBUF_FRAME_DESC {
+#ifdef BIG_ENDIAN_HOST
+	LM_UINT32 status_control;
+	union {
+		struct {
+			LM_UINT8 cqid;
+			LM_UINT8 reserved1;
+			LM_UINT16 length;
+		} s1;
+		LM_UINT32 word;
+	} u1;
+	union {
+		struct {
+			LM_UINT16 ip_hdr_start;
+			LM_UINT16 tcp_udp_hdr_start;
+		} s2;
+
+		LM_UINT32 word;
+	} u2;
+
+	union {
+		struct {
+			LM_UINT16 data_start;
+			LM_UINT16 vlan_id;
+		} s3;
+
+		LM_UINT32 word;
+	} u3;
+
+	union {
+		struct {
+			LM_UINT16 ip_checksum;
+			LM_UINT16 tcp_udp_checksum;
+		} s4;
+
+		LM_UINT32 word;
+	} u4;
+
+	union {
+		struct {
+			LM_UINT16 pseudo_checksum;
+			LM_UINT16 checksum_status;
+		} s5;
+
+		LM_UINT32 word;
+	} u5;
+
+	union {
+		struct {
+			LM_UINT16 rule_match;
+			LM_UINT8 class;
+			LM_UINT8 rupt;
+		} s6;
+
+		LM_UINT32 word;
+	} u6;
+
+	union {
+		struct {
+			LM_UINT16 reserved2;
+			LM_UINT16 mbuf_num;
+		} s7;
+
+		LM_UINT32 word;
+	} u7;
+
+	LM_UINT32 reserved3;
+	LM_UINT32 reserved4;
+#else
+	LM_UINT32 status_control;
+	union {
+		struct {
+			LM_UINT16 length;
+			LM_UINT8 reserved1;
+			LM_UINT8 cqid;
+		} s1;
+		LM_UINT32 word;
+	} u1;
+	union {
+		struct {
+			LM_UINT16 tcp_udp_hdr_start;
+			LM_UINT16 ip_hdr_start;
+		} s2;
+
+		LM_UINT32 word;
+	} u2;
+
+	union {
+		struct {
+			LM_UINT16 vlan_id;
+			LM_UINT16 data_start;
+		} s3;
+
+		LM_UINT32 word;
+	} u3;
+
+	union {
+		struct {
+			LM_UINT16 tcp_udp_checksum;
+			LM_UINT16 ip_checksum;
+		} s4;
+
+		LM_UINT32 word;
+	} u4;
+
+	union {
+		struct {
+			LM_UINT16 checksum_status;
+			LM_UINT16 pseudo_checksum;
+		} s5;
+
+		LM_UINT32 word;
+	} u5;
+
+	union {
+		struct {
+			LM_UINT8 rupt;
+			LM_UINT8 class;
+			LM_UINT16 rule_match;
+		} s6;
+
+		LM_UINT32 word;
+	} u6;
+
+	union {
+		struct {
+			LM_UINT16 mbuf_num;
+			LM_UINT16 reserved2;
+		} s7;
+
+		LM_UINT32 word;
+	} u7;
+
+	LM_UINT32 reserved3;
+	LM_UINT32 reserved4;
+#endif
+} T3_MBUF_FRAME_DESC, *PT3_MBUF_FRAME_DESC;
+
+typedef struct T3_MBUF_HDR {
+	union {
+		struct {
+			unsigned int C:1;
+			unsigned int F:1;
+			unsigned int reserved1:7;
+			unsigned int next_mbuf:16;
+			unsigned int length:7;
+		} s1;
+
+		LM_UINT32 word;
+	} u1;
+
+	LM_UINT32 next_frame_ptr;
+} T3_MBUF_HDR, *PT3_MBUF_HDR;
+
+typedef struct T3_MBUF {
+	T3_MBUF_HDR hdr;
+	union {
+		struct {
+			T3_MBUF_FRAME_DESC frame_hdr;
+			LM_UINT32 data[20];
+		} s1;
+
+		struct {
+			LM_UINT32 data[30];
+		} s2;
+	} body;
+} T3_MBUF, *PT3_MBUF;
+
+#define T3_MBUF_BASE   (T3_NIC_MBUF_POOL_ADDR >> 7)
+#define T3_MBUF_END    ((T3_NIC_MBUF_POOL_ADDR + T3_NIC_MBUF_POOL_SIZE) >> 7)
+
+/******************************************************************************/
+/* Statistics block. */
+/******************************************************************************/
+
+typedef struct {
+	LM_UINT8 Reserved0[0x400 - 0x300];
+
+	/* Statistics maintained by Receive MAC. */
+	T3_64BIT_REGISTER ifHCInOctets;
+	T3_64BIT_REGISTER Reserved1;
+	T3_64BIT_REGISTER etherStatsFragments;
+	T3_64BIT_REGISTER ifHCInUcastPkts;
+	T3_64BIT_REGISTER ifHCInMulticastPkts;
+	T3_64BIT_REGISTER ifHCInBroadcastPkts;
+	T3_64BIT_REGISTER dot3StatsFCSErrors;
+	T3_64BIT_REGISTER dot3StatsAlignmentErrors;
+	T3_64BIT_REGISTER xonPauseFramesReceived;
+	T3_64BIT_REGISTER xoffPauseFramesReceived;
+	T3_64BIT_REGISTER macControlFramesReceived;
+	T3_64BIT_REGISTER xoffStateEntered;
+	T3_64BIT_REGISTER dot3StatsFramesTooLong;
+	T3_64BIT_REGISTER etherStatsJabbers;
+	T3_64BIT_REGISTER etherStatsUndersizePkts;
+	T3_64BIT_REGISTER inRangeLengthError;
+	T3_64BIT_REGISTER outRangeLengthError;
+	T3_64BIT_REGISTER etherStatsPkts64Octets;
+	T3_64BIT_REGISTER etherStatsPkts65Octetsto127Octets;
+	T3_64BIT_REGISTER etherStatsPkts128Octetsto255Octets;
+	T3_64BIT_REGISTER etherStatsPkts256Octetsto511Octets;
+	T3_64BIT_REGISTER etherStatsPkts512Octetsto1023Octets;
+	T3_64BIT_REGISTER etherStatsPkts1024Octetsto1522Octets;
+	T3_64BIT_REGISTER etherStatsPkts1523Octetsto2047Octets;
+	T3_64BIT_REGISTER etherStatsPkts2048Octetsto4095Octets;
+	T3_64BIT_REGISTER etherStatsPkts4096Octetsto8191Octets;
+	T3_64BIT_REGISTER etherStatsPkts8192Octetsto9022Octets;
+
+	T3_64BIT_REGISTER Unused1[37];
+
+	/* Statistics maintained by Transmit MAC. */
+	T3_64BIT_REGISTER ifHCOutOctets;
+	T3_64BIT_REGISTER Reserved2;
+	T3_64BIT_REGISTER etherStatsCollisions;
+	T3_64BIT_REGISTER outXonSent;
+	T3_64BIT_REGISTER outXoffSent;
+	T3_64BIT_REGISTER flowControlDone;
+	T3_64BIT_REGISTER dot3StatsInternalMacTransmitErrors;
+	T3_64BIT_REGISTER dot3StatsSingleCollisionFrames;
+	T3_64BIT_REGISTER dot3StatsMultipleCollisionFrames;
+	T3_64BIT_REGISTER dot3StatsDeferredTransmissions;
+	T3_64BIT_REGISTER Reserved3;
+	T3_64BIT_REGISTER dot3StatsExcessiveCollisions;
+	T3_64BIT_REGISTER dot3StatsLateCollisions;
+	T3_64BIT_REGISTER dot3Collided2Times;
+	T3_64BIT_REGISTER dot3Collided3Times;
+	T3_64BIT_REGISTER dot3Collided4Times;
+	T3_64BIT_REGISTER dot3Collided5Times;
+	T3_64BIT_REGISTER dot3Collided6Times;
+	T3_64BIT_REGISTER dot3Collided7Times;
+	T3_64BIT_REGISTER dot3Collided8Times;
+	T3_64BIT_REGISTER dot3Collided9Times;
+	T3_64BIT_REGISTER dot3Collided10Times;
+	T3_64BIT_REGISTER dot3Collided11Times;
+	T3_64BIT_REGISTER dot3Collided12Times;
+	T3_64BIT_REGISTER dot3Collided13Times;
+	T3_64BIT_REGISTER dot3Collided14Times;
+	T3_64BIT_REGISTER dot3Collided15Times;
+	T3_64BIT_REGISTER ifHCOutUcastPkts;
+	T3_64BIT_REGISTER ifHCOutMulticastPkts;
+	T3_64BIT_REGISTER ifHCOutBroadcastPkts;
+	T3_64BIT_REGISTER dot3StatsCarrierSenseErrors;
+	T3_64BIT_REGISTER ifOutDiscards;
+	T3_64BIT_REGISTER ifOutErrors;
+
+	T3_64BIT_REGISTER Unused2[31];
+
+	/* Statistics maintained by Receive List Placement. */
+	T3_64BIT_REGISTER COSIfHCInPkts[16];
+	T3_64BIT_REGISTER COSFramesDroppedDueToFilters;
+	T3_64BIT_REGISTER nicDmaWriteQueueFull;
+	T3_64BIT_REGISTER nicDmaWriteHighPriQueueFull;
+	T3_64BIT_REGISTER nicNoMoreRxBDs;
+	T3_64BIT_REGISTER ifInDiscards;
+	T3_64BIT_REGISTER ifInErrors;
+	T3_64BIT_REGISTER nicRecvThresholdHit;
+
+	T3_64BIT_REGISTER Unused3[9];
+
+	/* Statistics maintained by Send Data Initiator. */
+	T3_64BIT_REGISTER COSIfHCOutPkts[16];
+	T3_64BIT_REGISTER nicDmaReadQueueFull;
+	T3_64BIT_REGISTER nicDmaReadHighPriQueueFull;
+	T3_64BIT_REGISTER nicSendDataCompQueueFull;
+
+	/* Statistics maintained by Host Coalescing. */
+	T3_64BIT_REGISTER nicRingSetSendProdIndex;
+	T3_64BIT_REGISTER nicRingStatusUpdate;
+	T3_64BIT_REGISTER nicInterrupts;
+	T3_64BIT_REGISTER nicAvoidedInterrupts;
+	T3_64BIT_REGISTER nicSendThresholdHit;
+
+	LM_UINT8 Reserved4[0xb00 - 0x9c0];
+} T3_STATS_BLOCK, *PT3_STATS_BLOCK;
+
+/******************************************************************************/
+/* PCI configuration registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_16BIT_REGISTER VendorId;
+	T3_16BIT_REGISTER DeviceId;
+
+	T3_16BIT_REGISTER Command;
+	T3_16BIT_REGISTER Status;
+
+	T3_32BIT_REGISTER ClassCodeRevId;
+
+	T3_8BIT_REGISTER CacheLineSize;
+	T3_8BIT_REGISTER LatencyTimer;
+	T3_8BIT_REGISTER HeaderType;
+	T3_8BIT_REGISTER Bist;
+
+	T3_32BIT_REGISTER MemBaseAddrLow;
+	T3_32BIT_REGISTER MemBaseAddrHigh;
+
+	LM_UINT8 Unused1[20];
+
+	T3_16BIT_REGISTER SubsystemVendorId;
+	T3_16BIT_REGISTER SubsystemId;
+
+	T3_32BIT_REGISTER RomBaseAddr;
+
+	T3_8BIT_REGISTER PciXCapiblityPtr;
+	LM_UINT8 Unused2[7];
+
+	T3_8BIT_REGISTER IntLine;
+	T3_8BIT_REGISTER IntPin;
+	T3_8BIT_REGISTER MinGnt;
+	T3_8BIT_REGISTER MaxLat;
+
+	T3_8BIT_REGISTER PciXCapabilities;
+	T3_8BIT_REGISTER PmCapabilityPtr;
+	T3_16BIT_REGISTER PciXCommand;
+
+	T3_32BIT_REGISTER PciXStatus;
+
+	T3_8BIT_REGISTER PmCapabilityId;
+	T3_8BIT_REGISTER VpdCapabilityPtr;
+	T3_16BIT_REGISTER PmCapabilities;
+
+	T3_16BIT_REGISTER PmCtrlStatus;
+#define PM_CTRL_PME_STATUS            BIT_15
+#define PM_CTRL_PME_ENABLE            BIT_8
+#define PM_CTRL_PME_POWER_STATE_D0    0
+#define PM_CTRL_PME_POWER_STATE_D1    1
+#define PM_CTRL_PME_POWER_STATE_D2    2
+#define PM_CTRL_PME_POWER_STATE_D3H   3
+
+	T3_8BIT_REGISTER BridgeSupportExt;
+	T3_8BIT_REGISTER PmData;
+
+	T3_8BIT_REGISTER VpdCapabilityId;
+	T3_8BIT_REGISTER MsiCapabilityPtr;
+	T3_16BIT_REGISTER VpdAddrFlag;
+#define VPD_FLAG_WRITE      (1 << 15)
+#define VPD_FLAG_RW_MASK    (1 << 15)
+#define VPD_FLAG_READ       0
+
+	T3_32BIT_REGISTER VpdData;
+
+	T3_8BIT_REGISTER MsiCapabilityId;
+	T3_8BIT_REGISTER NextCapabilityPtr;
+	T3_16BIT_REGISTER MsiCtrl;
+#define MSI_CTRL_64BIT_CAP     (1 << 7)
+#define MSI_CTRL_MSG_ENABLE(x) (x << 4)
+#define MSI_CTRL_MSG_CAP(x)    (x << 1)
+#define MSI_CTRL_ENABLE        (1 << 0)
+
+	T3_32BIT_REGISTER MsiAddrLow;
+	T3_32BIT_REGISTER MsiAddrHigh;
+
+	T3_16BIT_REGISTER MsiData;
+	T3_16BIT_REGISTER Unused3;
+
+	T3_32BIT_REGISTER MiscHostCtrl;
+#define MISC_HOST_CTRL_CLEAR_INT                        BIT_0
+#define MISC_HOST_CTRL_MASK_PCI_INT                     BIT_1
+#define MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP          BIT_2
+#define MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP          BIT_3
+#define MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW          BIT_4
+#define MISC_HOST_CTRL_ENABLE_CLK_REG_RW                BIT_5
+#define MISC_HOST_CTRL_ENABLE_REG_WORD_SWAP             BIT_6
+#define MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS           BIT_7
+#define MISC_HOST_CTRL_ENABLE_INT_MASK_MODE             BIT_8
+#define MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE        BIT_9
+
+	T3_32BIT_REGISTER DmaReadWriteCtrl;
+#define DMA_CTRL_WRITE_BOUNDARY_MASK            (BIT_11 | BIT_12 | BIT_13)
+#define DMA_CTRL_WRITE_BOUNDARY_DISABLE         0
+#define DMA_CTRL_WRITE_BOUNDARY_16              BIT_11
+#define DMA_CTRL_WRITE_BOUNDARY_32              BIT_12
+#define DMA_CTRL_WRITE_BOUNDARY_64              (BIT_12 | BIT_11)
+#define DMA_CTRL_WRITE_BOUNDARY_128             BIT_13
+#define DMA_CTRL_WRITE_BOUNDARY_256             (BIT_13 | BIT_11)
+#define DMA_CTRL_WRITE_BOUNDARY_512             (BIT_13 | BIT_12)
+#define DMA_CTRL_WRITE_BOUNDARY_1024            (BIT_13 | BIT_12 | BIT_11)
+#define DMA_CTRL_WRITE_ONE_DMA_AT_ONCE          BIT_14
+
+	T3_32BIT_REGISTER PciState;
+#define T3_PCI_STATE_FORCE_PCI_RESET                    BIT_0
+#define T3_PCI_STATE_INTERRUPT_NOT_ACTIVE               BIT_1
+#define T3_PCI_STATE_NOT_PCI_X_BUS                      BIT_2
+#define T3_PCI_STATE_HIGH_BUS_SPEED                     BIT_3
+#define T3_PCI_STATE_32BIT_PCI_BUS                      BIT_4
+#define T3_PCI_STATE_PCI_ROM_ENABLE                     BIT_5
+#define T3_PCI_STATE_PCI_ROM_RETRY_ENABLE               BIT_6
+#define T3_PCI_STATE_FLAT_VIEW                          BIT_8
+#define T3_PCI_STATE_RETRY_SAME_DMA                     BIT_13
+
+	T3_32BIT_REGISTER ClockCtrl;
+#define T3_PCI_CLKCTRL_TXCPU_CLK_DISABLE                BIT_11
+#define T3_PCI_CLKCTRL_RXCPU_CLK_DISABLE                BIT_10
+#define T3_PCI_CLKCTRL_CORE_CLK_DISABLE                 BIT_9
+
+	T3_32BIT_REGISTER RegBaseAddr;
+
+	T3_32BIT_REGISTER MemWindowBaseAddr;
+
+#ifdef NIC_CPU_VIEW
+	/* These registers are ONLY visible to NIC CPU */
+	T3_32BIT_REGISTER PowerConsumed;
+	T3_32BIT_REGISTER PowerDissipated;
+#else				/* NIC_CPU_VIEW */
+	T3_32BIT_REGISTER RegData;
+	T3_32BIT_REGISTER MemWindowData;
+#endif				/* !NIC_CPU_VIEW */
+
+	T3_32BIT_REGISTER ModeCtrl;
+
+	T3_32BIT_REGISTER MiscCfg;
+
+	T3_32BIT_REGISTER MiscLocalCtrl;
+
+	T3_32BIT_REGISTER Unused4;
+
+	/* NOTE: Big/Little-endian clarification needed.  Are these register */
+	/* in big or little endian formate. */
+	T3_64BIT_REGISTER StdRingProdIdx;
+	T3_64BIT_REGISTER RcvRetRingConIdx;
+	T3_64BIT_REGISTER SndProdIdx;
+
+	LM_UINT8 Unused5[80];
+} T3_PCI_CONFIGURATION, *PT3_PCI_CONFIGURATION;
+
+#define PCIX_CMD_MAX_SPLIT_MASK                         0x0070
+#define PCIX_CMD_MAX_SPLIT_SHL                          4
+#define PCIX_CMD_MAX_BURST_MASK                         0x000c
+#define PCIX_CMD_MAX_BURST_SHL                          2
+#define PCIX_CMD_MAX_BURST_CPIOB                        2
+
+/******************************************************************************/
+/* Mac control registers. */
+/******************************************************************************/
+
+typedef struct {
+	/* MAC mode control. */
+	T3_32BIT_REGISTER Mode;
+#define MAC_MODE_GLOBAL_RESET                       BIT_0
+#define MAC_MODE_HALF_DUPLEX                        BIT_1
+#define MAC_MODE_PORT_MODE_MASK                     (BIT_2 | BIT_3)
+#define MAC_MODE_PORT_MODE_TBI                      (BIT_2 | BIT_3)
+#define MAC_MODE_PORT_MODE_GMII                     BIT_3
+#define MAC_MODE_PORT_MODE_MII                      BIT_2
+#define MAC_MODE_PORT_MODE_NONE                     BIT_NONE
+#define MAC_MODE_PORT_INTERNAL_LOOPBACK             BIT_4
+#define MAC_MODE_TAGGED_MAC_CONTROL                 BIT_7
+#define MAC_MODE_TX_BURSTING                        BIT_8
+#define MAC_MODE_MAX_DEFER                          BIT_9
+#define MAC_MODE_LINK_POLARITY                      BIT_10
+#define MAC_MODE_ENABLE_RX_STATISTICS               BIT_11
+#define MAC_MODE_CLEAR_RX_STATISTICS                BIT_12
+#define MAC_MODE_FLUSH_RX_STATISTICS                BIT_13
+#define MAC_MODE_ENABLE_TX_STATISTICS               BIT_14
+#define MAC_MODE_CLEAR_TX_STATISTICS                BIT_15
+#define MAC_MODE_FLUSH_TX_STATISTICS                BIT_16
+#define MAC_MODE_SEND_CONFIGS                       BIT_17
+#define MAC_MODE_DETECT_MAGIC_PACKET_ENABLE         BIT_18
+#define MAC_MODE_ACPI_POWER_ON_ENABLE               BIT_19
+#define MAC_MODE_ENABLE_MIP                         BIT_20
+#define MAC_MODE_ENABLE_TDE                         BIT_21
+#define MAC_MODE_ENABLE_RDE                         BIT_22
+#define MAC_MODE_ENABLE_FHDE                        BIT_23
+
+	/* MAC status */
+	T3_32BIT_REGISTER Status;
+#define MAC_STATUS_PCS_SYNCED                       BIT_0
+#define MAC_STATUS_SIGNAL_DETECTED                  BIT_1
+#define MAC_STATUS_RECEIVING_CFG                    BIT_2
+#define MAC_STATUS_CFG_CHANGED                      BIT_3
+#define MAC_STATUS_SYNC_CHANGED                     BIT_4
+#define MAC_STATUS_PORT_DECODE_ERROR                BIT_10
+#define MAC_STATUS_LINK_STATE_CHANGED               BIT_12
+#define MAC_STATUS_MI_COMPLETION                    BIT_22
+#define MAC_STATUS_MI_INTERRUPT                     BIT_23
+#define MAC_STATUS_AP_ERROR                         BIT_24
+#define MAC_STATUS_ODI_ERROR                        BIT_25
+#define MAC_STATUS_RX_STATS_OVERRUN                 BIT_26
+#define MAC_STATUS_TX_STATS_OVERRUN                 BIT_27
+
+	/* Event Enable */
+	T3_32BIT_REGISTER MacEvent;
+#define MAC_EVENT_ENABLE_PORT_DECODE_ERR            BIT_10
+#define MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN    BIT_12
+#define MAC_EVENT_ENABLE_MI_COMPLETION              BIT_22
+#define MAC_EVENT_ENABLE_MI_INTERRUPT               BIT_23
+#define MAC_EVENT_ENABLE_AP_ERROR                   BIT_24
+#define MAC_EVENT_ENABLE_ODI_ERROR                  BIT_25
+#define MAC_EVENT_ENABLE_RX_STATS_OVERRUN           BIT_26
+#define MAC_EVENT_ENABLE_TX_STATS_OVERRUN           BIT_27
+
+	/* Led control. */
+	T3_32BIT_REGISTER LedCtrl;
+#define LED_CTRL_OVERRIDE_LINK_LED                  BIT_0
+#define LED_CTRL_1000MBPS_LED_ON                    BIT_1
+#define LED_CTRL_100MBPS_LED_ON                     BIT_2
+#define LED_CTRL_10MBPS_LED_ON                      BIT_3
+#define LED_CTRL_OVERRIDE_TRAFFIC_LED               BIT_4
+#define LED_CTRL_BLINK_TRAFFIC_LED                  BIT_5
+#define LED_CTRL_TRAFFIC_LED                        BIT_6
+#define LED_CTRL_1000MBPS_LED_STATUS                BIT_7
+#define LED_CTRL_100MBPS_LED_STATUS                 BIT_8
+#define LED_CTRL_10MBPS_LED_STATUS                  BIT_9
+#define LED_CTRL_TRAFFIC_LED_STATUS                 BIT_10
+#define LED_CTRL_MAC_MODE                           BIT_NONE
+#define LED_CTRL_PHY_MODE_1                         BIT_11
+#define LED_CTRL_PHY_MODE_2                         BIT_12
+#define LED_CTRL_BLINK_RATE_MASK                    0x7ff80000
+#define LED_CTRL_OVERRIDE_BLINK_PERIOD              BIT_19
+#define LED_CTRL_OVERRIDE_BLINK_RATE                BIT_31
+
+	/* MAC addresses. */
+	struct {
+		T3_32BIT_REGISTER High;	/* Upper 2 bytes. */
+		T3_32BIT_REGISTER Low;	/* Lower 4 bytes. */
+	} MacAddr[4];
+
+	/* ACPI Mbuf pointer. */
+	T3_32BIT_REGISTER AcpiMbufPtr;
+
+	/* ACPI Length and Offset. */
+	T3_32BIT_REGISTER AcpiLengthOffset;
+#define ACPI_LENGTH_MASK                            0xffff
+#define ACPI_OFFSET_MASK                            0x0fff0000
+#define ACPI_LENGTH(x)                              x
+#define ACPI_OFFSET(x)                              ((x) << 16)
+
+	/* Transmit random backoff. */
+	T3_32BIT_REGISTER TxBackoffSeed;
+#define MAC_TX_BACKOFF_SEED_MASK                    0x3ff
+
+	/* Receive MTU */
+	T3_32BIT_REGISTER MtuSize;
+#define MAC_RX_MTU_MASK                             0xffff
+
+	/* Gigabit PCS Test. */
+	T3_32BIT_REGISTER PcsTest;
+#define MAC_PCS_TEST_DATA_PATTERN_MASK              0x0fffff
+#define MAC_PCS_TEST_ENABLE                         BIT_20
+
+	/* Transmit Gigabit Auto-Negotiation. */
+	T3_32BIT_REGISTER TxAutoNeg;
+#define MAC_AN_TX_AN_DATA_MASK                      0xffff
+
+	/* Receive Gigabit Auto-Negotiation. */
+	T3_32BIT_REGISTER RxAutoNeg;
+#define MAC_AN_RX_AN_DATA_MASK                      0xffff
+
+	/* MI Communication. */
+	T3_32BIT_REGISTER MiCom;
+#define MI_COM_CMD_MASK                             (BIT_26 | BIT_27)
+#define MI_COM_CMD_WRITE                            BIT_26
+#define MI_COM_CMD_READ                             BIT_27
+#define MI_COM_READ_FAILED                          BIT_28
+#define MI_COM_START                                BIT_29
+#define MI_COM_BUSY                                 BIT_29
+
+#define MI_COM_PHY_ADDR_MASK                        0x1f
+#define MI_COM_FIRST_PHY_ADDR_BIT                   21
+
+#define MI_COM_PHY_REG_ADDR_MASK                    0x1f
+#define MI_COM_FIRST_PHY_REG_ADDR_BIT               16
+
+#define MI_COM_PHY_DATA_MASK                        0xffff
+
+	/* MI Status. */
+	T3_32BIT_REGISTER MiStatus;
+#define MI_STATUS_ENABLE_LINK_STATUS_ATTN           BIT_0
+
+	/* MI Mode. */
+	T3_32BIT_REGISTER MiMode;
+#define MI_MODE_CLOCK_SPEED_10MHZ                   BIT_0
+#define MI_MODE_USE_SHORT_PREAMBLE                  BIT_1
+#define MI_MODE_AUTO_POLLING_ENABLE                 BIT_4
+#define MI_MODE_CORE_CLOCK_SPEED_62MHZ              BIT_15
+
+	/* Auto-polling status. */
+	T3_32BIT_REGISTER AutoPollStatus;
+#define AUTO_POLL_ERROR                             BIT_0
+
+	/* Transmit MAC mode. */
+	T3_32BIT_REGISTER TxMode;
+#define TX_MODE_RESET                               BIT_0
+#define TX_MODE_ENABLE                              BIT_1
+#define TX_MODE_ENABLE_FLOW_CONTROL                 BIT_4
+#define TX_MODE_ENABLE_BIG_BACKOFF                  BIT_5
+#define TX_MODE_ENABLE_LONG_PAUSE                   BIT_6
+
+	/* Transmit MAC status. */
+	T3_32BIT_REGISTER TxStatus;
+#define TX_STATUS_RX_CURRENTLY_XOFFED               BIT_0
+#define TX_STATUS_SENT_XOFF                         BIT_1
+#define TX_STATUS_SENT_XON                          BIT_2
+#define TX_STATUS_LINK_UP                           BIT_3
+#define TX_STATUS_ODI_UNDERRUN                      BIT_4
+#define TX_STATUS_ODI_OVERRUN                       BIT_5
+
+	/* Transmit MAC length. */
+	T3_32BIT_REGISTER TxLengths;
+#define TX_LEN_SLOT_TIME_MASK                       0xff
+#define TX_LEN_IPG_MASK                             0x0f00
+#define TX_LEN_IPG_CRS_MASK                         (BIT_12 | BIT_13)
+
+	/* Receive MAC mode. */
+	T3_32BIT_REGISTER RxMode;
+#define RX_MODE_RESET                               BIT_0
+#define RX_MODE_ENABLE                              BIT_1
+#define RX_MODE_ENABLE_FLOW_CONTROL                 BIT_2
+#define RX_MODE_KEEP_MAC_CONTROL                    BIT_3
+#define RX_MODE_KEEP_PAUSE                          BIT_4
+#define RX_MODE_ACCEPT_OVERSIZED                    BIT_5
+#define RX_MODE_ACCEPT_RUNTS                        BIT_6
+#define RX_MODE_LENGTH_CHECK                        BIT_7
+#define RX_MODE_PROMISCUOUS_MODE                    BIT_8
+#define RX_MODE_NO_CRC_CHECK                        BIT_9
+#define RX_MODE_KEEP_VLAN_TAG                       BIT_10
+
+	/* Receive MAC status. */
+	T3_32BIT_REGISTER RxStatus;
+#define RX_STATUS_REMOTE_TRANSMITTER_XOFFED         BIT_0
+#define RX_STATUS_XOFF_RECEIVED                     BIT_1
+#define RX_STATUS_XON_RECEIVED                      BIT_2
+
+	/* Hash registers. */
+	T3_32BIT_REGISTER HashReg[4];
+
+	/* Receive placement rules registers. */
+	struct {
+		T3_32BIT_REGISTER Rule;
+		T3_32BIT_REGISTER Value;
+	} RcvRules[16];
+
+#define RCV_DISABLE_RULE_MASK                       0x7fffffff
+
+#define RCV_RULE1_REJECT_BROADCAST_IDX              0x00
+#define REJECT_BROADCAST_RULE1_RULE                 0xc2000000
+#define REJECT_BROADCAST_RULE1_VALUE                0xffffffff
+
+#define RCV_RULE2_REJECT_BROADCAST_IDX              0x01
+#define REJECT_BROADCAST_RULE2_RULE                 0x86000004
+#define REJECT_BROADCAST_RULE2_VALUE                0xffffffff
+
+#if INCLUDE_5701_AX_FIX
+#define RCV_LAST_RULE_IDX                           0x04
+#else
+#define RCV_LAST_RULE_IDX                           0x02
+#endif
+
+	T3_32BIT_REGISTER RcvRuleCfg;
+#define RX_RULE_DEFAULT_CLASS                       (1 << 3)
+
+	LM_UINT8 Reserved1[140];
+
+	T3_32BIT_REGISTER SerdesCfg;
+	T3_32BIT_REGISTER SerdesStatus;
+
+	LM_UINT8 Reserved2[104];
+
+	volatile LM_UINT8 TxMacState[16];
+	volatile LM_UINT8 RxMacState[20];
+
+	LM_UINT8 Reserved3[476];
+
+	T3_32BIT_REGISTER RxStats[26];
+
+	LM_UINT8 Reserved4[24];
+
+	T3_32BIT_REGISTER TxStats[28];
+
+	LM_UINT8 Reserved5[784];
+} T3_MAC_CONTROL, *PT3_MAC_CONTROL;
+
+/******************************************************************************/
+/* Send data initiator control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define T3_SND_DATA_IN_MODE_RESET                       BIT_0
+#define T3_SND_DATA_IN_MODE_ENABLE                      BIT_1
+#define T3_SND_DATA_IN_MODE_STATS_OFLW_ATTN_ENABLE      BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define T3_SND_DATA_IN_STATUS_STATS_OFLW_ATTN           BIT_2
+
+	T3_32BIT_REGISTER StatsCtrl;
+#define T3_SND_DATA_IN_STATS_CTRL_ENABLE                BIT_0
+#define T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE         BIT_1
+#define T3_SND_DATA_IN_STATS_CTRL_CLEAR                 BIT_2
+#define T3_SND_DATA_IN_STATS_CTRL_FLUSH                 BIT_3
+#define T3_SND_DATA_IN_STATS_CTRL_FORCE_ZERO            BIT_4
+
+	T3_32BIT_REGISTER StatsEnableMask;
+	T3_32BIT_REGISTER StatsIncMask;
+
+	LM_UINT8 Reserved[108];
+
+	T3_32BIT_REGISTER ClassOfServCnt[16];
+	T3_32BIT_REGISTER DmaReadQFullCnt;
+	T3_32BIT_REGISTER DmaPriorityReadQFullCnt;
+	T3_32BIT_REGISTER SdcQFullCnt;
+
+	T3_32BIT_REGISTER NicRingSetSendProdIdxCnt;
+	T3_32BIT_REGISTER StatusUpdatedCnt;
+	T3_32BIT_REGISTER InterruptsCnt;
+	T3_32BIT_REGISTER AvoidInterruptsCnt;
+	T3_32BIT_REGISTER SendThresholdHitCnt;
+
+	/* Unused space. */
+	LM_UINT8 Unused[800];
+} T3_SEND_DATA_INITIATOR, *PT3_SEND_DATA_INITIATOR;
+
+/******************************************************************************/
+/* Send data completion control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define SND_DATA_COMP_MODE_RESET                        BIT_0
+#define SND_DATA_COMP_MODE_ENABLE                       BIT_1
+
+	/* Unused space. */
+	LM_UINT8 Unused[1020];
+} T3_SEND_DATA_COMPLETION, *PT3_SEND_DATA_COMPLETION;
+
+/******************************************************************************/
+/* Send BD Ring Selector Control Registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define SND_BD_SEL_MODE_RESET                           BIT_0
+#define SND_BD_SEL_MODE_ENABLE                          BIT_1
+#define SND_BD_SEL_MODE_ATTN_ENABLE                     BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define SND_BD_SEL_STATUS_ERROR_ATTN                    BIT_2
+
+	T3_32BIT_REGISTER HwDiag;
+
+	/* Unused space. */
+	LM_UINT8 Unused1[52];
+
+	/* Send BD Ring Selector Local NIC Send BD Consumer Index. */
+	T3_32BIT_REGISTER NicSendBdSelConIdx[16];
+
+	/* Unused space. */
+	LM_UINT8 Unused2[896];
+} T3_SEND_BD_SELECTOR, *PT3_SEND_BD_SELECTOR;
+
+/******************************************************************************/
+/* Send BD initiator control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define SND_BD_IN_MODE_RESET                            BIT_0
+#define SND_BD_IN_MODE_ENABLE                           BIT_1
+#define SND_BD_IN_MODE_ATTN_ENABLE                      BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define SND_BD_IN_STATUS_ERROR_ATTN                     BIT_2
+
+	/* Send BD initiator local NIC send BD producer index. */
+	T3_32BIT_REGISTER NicSendBdInProdIdx[16];
+
+	/* Unused space. */
+	LM_UINT8 Unused2[952];
+} T3_SEND_BD_INITIATOR, *PT3_SEND_BD_INITIATOR;
+
+/******************************************************************************/
+/* Send BD Completion Control. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define SND_BD_COMP_MODE_RESET                          BIT_0
+#define SND_BD_COMP_MODE_ENABLE                         BIT_1
+#define SND_BD_COMP_MODE_ATTN_ENABLE                    BIT_2
+
+	/* Unused space. */
+	LM_UINT8 Unused2[1020];
+} T3_SEND_BD_COMPLETION, *PT3_SEND_BD_COMPLETION;
+
+/******************************************************************************/
+/* Receive list placement control registers. */
+/******************************************************************************/
+
+typedef struct {
+	/* Mode. */
+	T3_32BIT_REGISTER Mode;
+#define RCV_LIST_PLMT_MODE_RESET                        BIT_0
+#define RCV_LIST_PLMT_MODE_ENABLE                       BIT_1
+#define RCV_LIST_PLMT_MODE_CLASS0_ATTN_ENABLE           BIT_2
+#define RCV_LIST_PLMT_MODE_MAPPING_OOR_ATTN_ENABLE      BIT_3
+#define RCV_LIST_PLMT_MODE_STATS_OFLOW_ATTN_ENABLE      BIT_4
+
+	/* Status. */
+	T3_32BIT_REGISTER Status;
+#define RCV_LIST_PLMT_STATUS_CLASS0_ATTN                BIT_2
+#define RCV_LIST_PLMT_STATUS_MAPPING_ATTN               BIT_3
+#define RCV_LIST_PLMT_STATUS_STATS_OFLOW_ATTN           BIT_4
+
+	/* Receive selector list lock register. */
+	T3_32BIT_REGISTER Lock;
+#define RCV_LIST_SEL_LOCK_REQUEST_MASK                  0xffff
+#define RCV_LIST_SEL_LOCK_GRANT_MASK                    0xffff0000
+
+	/* Selector non-empty bits. */
+	T3_32BIT_REGISTER NonEmptyBits;
+#define RCV_LIST_SEL_NON_EMPTY_MASK                     0xffff
+
+	/* Receive list placement configuration register. */
+	T3_32BIT_REGISTER Config;
+
+	/* Receive List Placement statistics Control. */
+	T3_32BIT_REGISTER StatsCtrl;
+#define RCV_LIST_STATS_ENABLE                               BIT_0
+#define RCV_LIST_STATS_FAST_UPDATE                          BIT_1
+
+	/* Receive List Placement statistics Enable Mask. */
+	T3_32BIT_REGISTER StatsEnableMask;
+
+	/* Receive List Placement statistics Increment Mask. */
+	T3_32BIT_REGISTER StatsIncMask;
+
+	/* Unused space. */
+	LM_UINT8 Unused1[224];
+
+	struct {
+		T3_32BIT_REGISTER Head;
+		T3_32BIT_REGISTER Tail;
+		T3_32BIT_REGISTER Count;
+
+		/* Unused space. */
+		LM_UINT8 Unused[4];
+	} RcvSelectorList[16];
+
+	/* Local statistics counter. */
+	T3_32BIT_REGISTER ClassOfServCnt[16];
+
+	T3_32BIT_REGISTER DropDueToFilterCnt;
+	T3_32BIT_REGISTER DmaWriteQFullCnt;
+	T3_32BIT_REGISTER DmaHighPriorityWriteQFullCnt;
+	T3_32BIT_REGISTER NoMoreReceiveBdCnt;
+	T3_32BIT_REGISTER IfInDiscardsCnt;
+	T3_32BIT_REGISTER IfInErrorsCnt;
+	T3_32BIT_REGISTER RcvThresholdHitCnt;
+
+	/* Another unused space. */
+	LM_UINT8 Unused2[420];
+} T3_RCV_LIST_PLACEMENT, *PT3_RCV_LIST_PLACEMENT;
+
+/******************************************************************************/
+/* Receive Data and Receive BD Initiator Control. */
+/******************************************************************************/
+
+typedef struct {
+	/* Mode. */
+	T3_32BIT_REGISTER Mode;
+#define RCV_DATA_BD_IN_MODE_RESET                   BIT_0
+#define RCV_DATA_BD_IN_MODE_ENABLE                  BIT_1
+#define RCV_DATA_BD_IN_MODE_JUMBO_BD_NEEDED         BIT_2
+#define RCV_DATA_BD_IN_MODE_FRAME_TOO_BIG           BIT_3
+#define RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE       BIT_4
+
+	/* Status. */
+	T3_32BIT_REGISTER Status;
+#define RCV_DATA_BD_IN_STATUS_JUMBO_BD_NEEDED       BIT_2
+#define RCV_DATA_BD_IN_STATUS_FRAME_TOO_BIG         BIT_3
+#define RCV_DATA_BD_IN_STATUS_INVALID_RING_SIZE     BIT_4
+
+	/* Split frame minium size. */
+	T3_32BIT_REGISTER SplitFrameMinSize;
+
+	/* Unused space. */
+	LM_UINT8 Unused1[0x2440 - 0x240c];
+
+	/* Receive RCBs. */
+	T3_RCB JumboRcvRcb;
+	T3_RCB StdRcvRcb;
+	T3_RCB MiniRcvRcb;
+
+	/* Receive Data and Receive BD Ring Initiator Local NIC Receive */
+	/* BD Consumber Index. */
+	T3_32BIT_REGISTER NicJumboConIdx;
+	T3_32BIT_REGISTER NicStdConIdx;
+	T3_32BIT_REGISTER NicMiniConIdx;
+
+	/* Unused space. */
+	LM_UINT8 Unused2[4];
+
+	/* Receive Data and Receive BD Initiator Local Receive Return ProdIdx. */
+	T3_32BIT_REGISTER RcvDataBdProdIdx[16];
+
+	/* Receive Data and Receive BD Initiator Hardware Diagnostic. */
+	T3_32BIT_REGISTER HwDiag;
+
+	/* Unused space. */
+	LM_UINT8 Unused3[828];
+} T3_RCV_DATA_BD_INITIATOR, *PT3_RCV_DATA_BD_INITIATOR;
+
+/******************************************************************************/
+/* Receive Data Completion Control Registes. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define RCV_DATA_COMP_MODE_RESET                        BIT_0
+#define RCV_DATA_COMP_MODE_ENABLE                       BIT_1
+#define RCV_DATA_COMP_MODE_ATTN_ENABLE                  BIT_2
+
+	/* Unused spaced. */
+	LM_UINT8 Unused[1020];
+} T3_RCV_DATA_COMPLETION, *PT3_RCV_DATA_COMPLETION;
+
+/******************************************************************************/
+/* Receive BD Initiator Control. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define RCV_BD_IN_MODE_RESET                            BIT_0
+#define RCV_BD_IN_MODE_ENABLE                           BIT_1
+#define RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE    BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define RCV_BD_IN_STATUS_BD_IN_DIABLED_RCB_ATTN         BIT_2
+
+	T3_32BIT_REGISTER NicJumboRcvProdIdx;
+	T3_32BIT_REGISTER NicStdRcvProdIdx;
+	T3_32BIT_REGISTER NicMiniRcvProdIdx;
+
+	T3_32BIT_REGISTER MiniRcvThreshold;
+	T3_32BIT_REGISTER StdRcvThreshold;
+	T3_32BIT_REGISTER JumboRcvThreshold;
+
+	/* Unused space. */
+	LM_UINT8 Unused[992];
+} T3_RCV_BD_INITIATOR, *PT3_RCV_BD_INITIATOR;
+
+/******************************************************************************/
+/* Receive BD Completion Control Registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define RCV_BD_COMP_MODE_RESET                          BIT_0
+#define RCV_BD_COMP_MODE_ENABLE                         BIT_1
+#define RCV_BD_COMP_MODE_ATTN_ENABLE                    BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define RCV_BD_COMP_STATUS_ERROR_ATTN                   BIT_2
+
+	T3_32BIT_REGISTER NicJumboRcvBdProdIdx;
+	T3_32BIT_REGISTER NicStdRcvBdProdIdx;
+	T3_32BIT_REGISTER NicMiniRcvBdProdIdx;
+
+	/* Unused space. */
+	LM_UINT8 Unused[1004];
+} T3_RCV_BD_COMPLETION, *PT3_RCV_BD_COMPLETION;
+
+/******************************************************************************/
+/* Receive list selector control register. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define RCV_LIST_SEL_MODE_RESET                         BIT_0
+#define RCV_LIST_SEL_MODE_ENABLE                        BIT_1
+#define RCV_LIST_SEL_MODE_ATTN_ENABLE                   BIT_2
+
+	T3_32BIT_REGISTER Status;
+#define RCV_LIST_SEL_STATUS_ERROR_ATTN                  BIT_2
+
+	/* Unused space. */
+	LM_UINT8 Unused[1016];
+} T3_RCV_LIST_SELECTOR, *PT3_RCV_LIST_SELECTOR;
+
+/******************************************************************************/
+/* Mbuf cluster free registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define MBUF_CLUSTER_FREE_MODE_RESET    BIT_0
+#define MBUF_CLUSTER_FREE_MODE_ENABLE   BIT_1
+
+	T3_32BIT_REGISTER Status;
+
+	/* Unused space. */
+	LM_UINT8 Unused[1016];
+} T3_MBUF_CLUSTER_FREE, *PT3_MBUF_CLUSTER_FREE;
+
+/******************************************************************************/
+/* Host coalescing control registers. */
+/******************************************************************************/
+
+typedef struct {
+	/* Mode. */
+	T3_32BIT_REGISTER Mode;
+#define HOST_COALESCE_RESET                         BIT_0
+#define HOST_COALESCE_ENABLE                        BIT_1
+#define HOST_COALESCE_ATTN                          BIT_2
+#define HOST_COALESCE_NOW                           BIT_3
+#define HOST_COALESCE_FULL_STATUS_MODE              BIT_NONE
+#define HOST_COALESCE_64_BYTE_STATUS_MODE           BIT_7
+#define HOST_COALESCE_32_BYTE_STATUS_MODE           BIT_8
+#define HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT    BIT_9
+#define HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT    BIT_10
+#define HOST_COALESCE_NO_INT_ON_COALESCE_NOW_MODE   BIT_11
+#define HOST_COALESCE_NO_INT_ON_FORCE_DMAD_MODE     BIT_12
+
+	/* Status. */
+	T3_32BIT_REGISTER Status;
+#define HOST_COALESCE_ERROR_ATTN                    BIT_2
+
+	/* Receive coalescing ticks. */
+	T3_32BIT_REGISTER RxCoalescingTicks;
+
+	/* Send coalescing ticks. */
+	T3_32BIT_REGISTER TxCoalescingTicks;
+
+	/* Receive max coalesced frames. */
+	T3_32BIT_REGISTER RxMaxCoalescedFrames;
+
+	/* Send max coalesced frames. */
+	T3_32BIT_REGISTER TxMaxCoalescedFrames;
+
+	/* Receive coalescing ticks during interrupt. */
+	T3_32BIT_REGISTER RxCoalescedTickDuringInt;
+
+	/* Send coalescing ticks during interrupt. */
+	T3_32BIT_REGISTER TxCoalescedTickDuringInt;
+
+	/* Receive max coalesced frames during interrupt. */
+	T3_32BIT_REGISTER RxMaxCoalescedFramesDuringInt;
+
+	/* Send max coalesced frames during interrupt. */
+	T3_32BIT_REGISTER TxMaxCoalescedFramesDuringInt;
+
+	/* Statistics tick. */
+	T3_32BIT_REGISTER StatsCoalescingTicks;
+
+	/* Unused space. */
+	LM_UINT8 Unused2[4];
+
+	/* Statistics host address. */
+	T3_64BIT_REGISTER StatsBlkHostAddr;
+
+	/* Status block host address. */
+	T3_64BIT_REGISTER StatusBlkHostAddr;
+
+	/* Statistics NIC address. */
+	T3_32BIT_REGISTER StatsBlkNicAddr;
+
+	/* Statust block NIC address. */
+	T3_32BIT_REGISTER StatusBlkNicAddr;
+
+	/* Flow attention registers. */
+	T3_32BIT_REGISTER FlowAttn;
+
+	/* Unused space. */
+	LM_UINT8 Unused3[4];
+
+	T3_32BIT_REGISTER NicJumboRcvBdConIdx;
+	T3_32BIT_REGISTER NicStdRcvBdConIdx;
+	T3_32BIT_REGISTER NicMiniRcvBdConIdx;
+
+	/* Unused space. */
+	LM_UINT8 Unused4[36];
+
+	T3_32BIT_REGISTER NicRetProdIdx[16];
+	T3_32BIT_REGISTER NicSndBdConIdx[16];
+
+	/* Unused space. */
+	LM_UINT8 Unused5[768];
+} T3_HOST_COALESCING, *PT3_HOST_COALESCING;
+
+/******************************************************************************/
+/* Memory arbiter registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define T3_MEM_ARBITER_MODE_RESET       BIT_0
+#define T3_MEM_ARBITER_MODE_ENABLE      BIT_1
+
+	T3_32BIT_REGISTER Status;
+
+	T3_32BIT_REGISTER ArbTrapAddrLow;
+	T3_32BIT_REGISTER ArbTrapAddrHigh;
+
+	/* Unused space. */
+	LM_UINT8 Unused[1008];
+} T3_MEM_ARBITER, *PT3_MEM_ARBITER;
+
+/******************************************************************************/
+/* Buffer manager control register. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define BUFMGR_MODE_RESET                           BIT_0
+#define BUFMGR_MODE_ENABLE                          BIT_1
+#define BUFMGR_MODE_ATTN_ENABLE                     BIT_2
+#define BUFMGR_MODE_BM_TEST                         BIT_3
+#define BUFMGR_MODE_MBUF_LOW_ATTN_ENABLE            BIT_4
+
+	T3_32BIT_REGISTER Status;
+#define BUFMGR_STATUS_ERROR                         BIT_2
+#define BUFMGR_STATUS_MBUF_LOW                      BIT_4
+
+	T3_32BIT_REGISTER MbufPoolAddr;
+	T3_32BIT_REGISTER MbufPoolSize;
+	T3_32BIT_REGISTER MbufReadDmaLowWaterMark;
+	T3_32BIT_REGISTER MbufMacRxLowWaterMark;
+	T3_32BIT_REGISTER MbufHighWaterMark;
+
+	T3_32BIT_REGISTER RxCpuMbufAllocReq;
+#define BUFMGR_MBUF_ALLOC_BIT                     BIT_31
+	T3_32BIT_REGISTER RxCpuMbufAllocResp;
+	T3_32BIT_REGISTER TxCpuMbufAllocReq;
+	T3_32BIT_REGISTER TxCpuMbufAllocResp;
+
+	T3_32BIT_REGISTER DmaDescPoolAddr;
+	T3_32BIT_REGISTER DmaDescPoolSize;
+	T3_32BIT_REGISTER DmaLowWaterMark;
+	T3_32BIT_REGISTER DmaHighWaterMark;
+
+	T3_32BIT_REGISTER RxCpuDmaAllocReq;
+	T3_32BIT_REGISTER RxCpuDmaAllocResp;
+	T3_32BIT_REGISTER TxCpuDmaAllocReq;
+	T3_32BIT_REGISTER TxCpuDmaAllocResp;
+
+	T3_32BIT_REGISTER Hwdiag[3];
+
+	/* Unused space. */
+	LM_UINT8 Unused[936];
+} T3_BUFFER_MANAGER, *PT3_BUFFER_MANAGER;
+
+/******************************************************************************/
+/* Read DMA control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define DMA_READ_MODE_RESET                         BIT_0
+#define DMA_READ_MODE_ENABLE                        BIT_1
+#define DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE      BIT_2
+#define DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE      BIT_3
+#define DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE      BIT_4
+#define DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE     BIT_5
+#define DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE      BIT_6
+#define DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE     BIT_7
+#define DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE     BIT_8
+#define DMA_READ_MODE_LONG_READ_ATTN_ENABLE         BIT_9
+#define DMA_READ_MODE_SPLIT_ENABLE                  BIT_11
+#define DMA_READ_MODE_SPLIT_RESET                   BIT_12
+
+	T3_32BIT_REGISTER Status;
+#define DMA_READ_STATUS_TARGET_ABORT_ATTN           BIT_2
+#define DMA_READ_STATUS_MASTER_ABORT_ATTN           BIT_3
+#define DMA_READ_STATUS_PARITY_ERROR_ATTN           BIT_4
+#define DMA_READ_STATUS_ADDR_OVERFLOW_ATTN          BIT_5
+#define DMA_READ_STATUS_FIFO_OVERRUN_ATTN           BIT_6
+#define DMA_READ_STATUS_FIFO_UNDERRUN_ATTN          BIT_7
+#define DMA_READ_STATUS_FIFO_OVERREAD_ATTN          BIT_8
+#define DMA_READ_STATUS_LONG_READ_ATTN              BIT_9
+
+	/* Unused space. */
+	LM_UINT8 Unused[1016];
+} T3_DMA_READ, *PT3_DMA_READ;
+
+typedef union T3_CPU {
+	struct {
+		T3_32BIT_REGISTER mode;
+#define CPU_MODE_HALT   BIT_10
+#define CPU_MODE_RESET  BIT_0
+		T3_32BIT_REGISTER state;
+		T3_32BIT_REGISTER EventMask;
+		T3_32BIT_REGISTER reserved1[4];
+		T3_32BIT_REGISTER PC;
+		T3_32BIT_REGISTER Instruction;
+		T3_32BIT_REGISTER SpadUnderflow;
+		T3_32BIT_REGISTER WatchdogClear;
+		T3_32BIT_REGISTER WatchdogVector;
+		T3_32BIT_REGISTER WatchdogSavedPC;
+		T3_32BIT_REGISTER HardwareBp;
+		T3_32BIT_REGISTER reserved2[3];
+		T3_32BIT_REGISTER WatchdogSavedState;
+		T3_32BIT_REGISTER LastBrchAddr;
+		T3_32BIT_REGISTER SpadUnderflowSet;
+		T3_32BIT_REGISTER reserved3[(0x200 - 0x50) / 4];
+		T3_32BIT_REGISTER Regs[32];
+		T3_32BIT_REGISTER reserved4[(0x400 - 0x280) / 4];
+	} reg;
+} T3_CPU, *PT3_CPU;
+
+/******************************************************************************/
+/* Write DMA control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define DMA_WRITE_MODE_RESET                        BIT_0
+#define DMA_WRITE_MODE_ENABLE                       BIT_1
+#define DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE     BIT_2
+#define DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE     BIT_3
+#define DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE     BIT_4
+#define DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE    BIT_5
+#define DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE     BIT_6
+#define DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE    BIT_7
+#define DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE    BIT_8
+#define DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE        BIT_9
+
+	T3_32BIT_REGISTER Status;
+#define DMA_WRITE_STATUS_TARGET_ABORT_ATTN          BIT_2
+#define DMA_WRITE_STATUS_MASTER_ABORT_ATTN          BIT_3
+#define DMA_WRITE_STATUS_PARITY_ERROR_ATTN          BIT_4
+#define DMA_WRITE_STATUS_ADDR_OVERFLOW_ATTN         BIT_5
+#define DMA_WRITE_STATUS_FIFO_OVERRUN_ATTN          BIT_6
+#define DMA_WRITE_STATUS_FIFO_UNDERRUN_ATTN         BIT_7
+#define DMA_WRITE_STATUS_FIFO_OVERREAD_ATTN         BIT_8
+#define DMA_WRITE_STATUS_LONG_READ_ATTN             BIT_9
+
+	/* Unused space. */
+	LM_UINT8 Unused[1016];
+} T3_DMA_WRITE, *PT3_DMA_WRITE;
+
+/******************************************************************************/
+/* Mailbox registers. */
+/******************************************************************************/
+
+typedef struct {
+	/* Interrupt mailbox registers. */
+	T3_64BIT_REGISTER Interrupt[4];
+
+	/* General mailbox registers. */
+	T3_64BIT_REGISTER General[8];
+
+	/* Reload statistics mailbox. */
+	T3_64BIT_REGISTER ReloadStat;
+
+	/* Receive BD ring producer index registers. */
+	T3_64BIT_REGISTER RcvStdProdIdx;
+	T3_64BIT_REGISTER RcvJumboProdIdx;
+	T3_64BIT_REGISTER RcvMiniProdIdx;
+
+	/* Receive return ring consumer index registers. */
+	T3_64BIT_REGISTER RcvRetConIdx[16];
+
+	/* Send BD ring host producer index registers. */
+	T3_64BIT_REGISTER SendHostProdIdx[16];
+
+	/* Send BD ring nic producer index registers. */
+	T3_64BIT_REGISTER SendNicProdIdx[16];
+} T3_MAILBOX, *PT3_MAILBOX;
+
+typedef struct {
+	T3_MAILBOX Mailbox;
+
+	/* Priority mailbox registers. */
+	T3_32BIT_REGISTER HighPriorityEventVector;
+	T3_32BIT_REGISTER HighPriorityEventMask;
+	T3_32BIT_REGISTER LowPriorityEventVector;
+	T3_32BIT_REGISTER LowPriorityEventMask;
+
+	/* Unused space. */
+	LM_UINT8 Unused[496];
+} T3_GRC_MAILBOX, *PT3_GRC_MAILBOX;
+
+/******************************************************************************/
+/* Flow through queues. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Reset;
+
+	LM_UINT8 Unused[12];
+
+	T3_32BIT_REGISTER DmaNormalReadFtqCtrl;
+	T3_32BIT_REGISTER DmaNormalReadFtqFullCnt;
+	T3_32BIT_REGISTER DmaNormalReadFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER DmaNormalReadFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER DmaHighReadFtqCtrl;
+	T3_32BIT_REGISTER DmaHighReadFtqFullCnt;
+	T3_32BIT_REGISTER DmaHighReadFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER DmaHighReadFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER DmaCompDiscardFtqCtrl;
+	T3_32BIT_REGISTER DmaCompDiscardFtqFullCnt;
+	T3_32BIT_REGISTER DmaCompDiscardFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER DmaCompDiscardFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER SendBdCompFtqCtrl;
+	T3_32BIT_REGISTER SendBdCompFtqFullCnt;
+	T3_32BIT_REGISTER SendBdCompFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER SendBdCompFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER SendDataInitiatorFtqCtrl;
+	T3_32BIT_REGISTER SendDataInitiatorFtqFullCnt;
+	T3_32BIT_REGISTER SendDataInitiatorFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER SendDataInitiatorFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER DmaNormalWriteFtqCtrl;
+	T3_32BIT_REGISTER DmaNormalWriteFtqFullCnt;
+	T3_32BIT_REGISTER DmaNormalWriteFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER DmaNormalWriteFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER DmaHighWriteFtqCtrl;
+	T3_32BIT_REGISTER DmaHighWriteFtqFullCnt;
+	T3_32BIT_REGISTER DmaHighWriteFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER DmaHighWriteFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER SwType1FtqCtrl;
+	T3_32BIT_REGISTER SwType1FtqFullCnt;
+	T3_32BIT_REGISTER SwType1FtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER SwType1FtqFifoWritePeek;
+
+	T3_32BIT_REGISTER SendDataCompFtqCtrl;
+	T3_32BIT_REGISTER SendDataCompFtqFullCnt;
+	T3_32BIT_REGISTER SendDataCompFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER SendDataCompFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER HostCoalesceFtqCtrl;
+	T3_32BIT_REGISTER HostCoalesceFtqFullCnt;
+	T3_32BIT_REGISTER HostCoalesceFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER HostCoalesceFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER MacTxFtqCtrl;
+	T3_32BIT_REGISTER MacTxFtqFullCnt;
+	T3_32BIT_REGISTER MacTxFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER MacTxFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER MbufClustFreeFtqCtrl;
+	T3_32BIT_REGISTER MbufClustFreeFtqFullCnt;
+	T3_32BIT_REGISTER MbufClustFreeFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER MbufClustFreeFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER RcvBdCompFtqCtrl;
+	T3_32BIT_REGISTER RcvBdCompFtqFullCnt;
+	T3_32BIT_REGISTER RcvBdCompFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER RcvBdCompFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER RcvListPlmtFtqCtrl;
+	T3_32BIT_REGISTER RcvListPlmtFtqFullCnt;
+	T3_32BIT_REGISTER RcvListPlmtFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER RcvListPlmtFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER RcvDataBdInitiatorFtqCtrl;
+	T3_32BIT_REGISTER RcvDataBdInitiatorFtqFullCnt;
+	T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER RcvDataCompFtqCtrl;
+	T3_32BIT_REGISTER RcvDataCompFtqFullCnt;
+	T3_32BIT_REGISTER RcvDataCompFtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER RcvDataCompFtqFifoWritePeek;
+
+	T3_32BIT_REGISTER SwType2FtqCtrl;
+	T3_32BIT_REGISTER SwType2FtqFullCnt;
+	T3_32BIT_REGISTER SwType2FtqFifoEnqueueDequeue;
+	T3_32BIT_REGISTER SwType2FtqFifoWritePeek;
+
+	/* Unused space. */
+	LM_UINT8 Unused2[736];
+} T3_FTQ, *PT3_FTQ;
+
+/******************************************************************************/
+/* Message signaled interrupt registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define MSI_MODE_RESET       BIT_0
+#define MSI_MODE_ENABLE      BIT_1
+	T3_32BIT_REGISTER Status;
+
+	T3_32BIT_REGISTER MsiFifoAccess;
+
+	/* Unused space. */
+	LM_UINT8 Unused[1012];
+} T3_MSG_SIGNALED_INT, *PT3_MSG_SIGNALED_INT;
+
+/******************************************************************************/
+/* DMA Completion registes. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Mode;
+#define DMA_COMP_MODE_RESET                         BIT_0
+#define DMA_COMP_MODE_ENABLE                        BIT_1
+
+	/* Unused space. */
+	LM_UINT8 Unused[1020];
+} T3_DMA_COMPLETION, *PT3_DMA_COMPLETION;
+
+/******************************************************************************/
+/* GRC registers. */
+/******************************************************************************/
+
+typedef struct {
+	/* Mode control register. */
+	T3_32BIT_REGISTER Mode;
+#define GRC_MODE_UPDATE_ON_COALESCING               BIT_0
+#define GRC_MODE_BYTE_SWAP_NON_FRAME_DATA           BIT_1
+#define GRC_MODE_WORD_SWAP_NON_FRAME_DATA           BIT_2
+#define GRC_MODE_BYTE_SWAP_DATA                     BIT_4
+#define GRC_MODE_WORD_SWAP_DATA                     BIT_5
+#define GRC_MODE_SPLIT_HEADER_MODE                  BIT_8
+#define GRC_MODE_NO_FRAME_CRACKING                  BIT_9
+#define GRC_MODE_INCLUDE_CRC                        BIT_10
+#define GRC_MODE_ALLOW_BAD_FRAMES                   BIT_11
+#define GRC_MODE_NO_INTERRUPT_ON_SENDS              BIT_13
+#define GRC_MODE_NO_INTERRUPT_ON_RECEIVE            BIT_14
+#define GRC_MODE_FORCE_32BIT_PCI_BUS_MODE           BIT_15
+#define GRC_MODE_HOST_STACK_UP                      BIT_16
+#define GRC_MODE_HOST_SEND_BDS                      BIT_17
+#define GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM         BIT_20
+#define GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM         BIT_23
+#define GRC_MODE_INT_ON_TX_CPU_ATTN                 BIT_24
+#define GRC_MODE_INT_ON_RX_CPU_ATTN                 BIT_25
+#define GRC_MODE_INT_ON_MAC_ATTN                    BIT_26
+#define GRC_MODE_INT_ON_DMA_ATTN                    BIT_27
+#define GRC_MODE_INT_ON_FLOW_ATTN                   BIT_28
+#define GRC_MODE_4X_NIC_BASED_SEND_RINGS            BIT_29
+#define GRC_MODE_MULTICAST_FRAME_ENABLE             BIT_30
+
+	/* Misc configuration register. */
+	T3_32BIT_REGISTER MiscCfg;
+#define GRC_MISC_CFG_CORE_CLOCK_RESET               BIT_0
+#define GRC_MISC_PRESCALAR_TIMER_MASK               0xfe
+#define GRC_MISC_BD_ID_MASK                         0x0001e000
+#define GRC_MISC_BD_ID_5700                         0x0001e000
+#define GRC_MISC_BD_ID_5701                         0x00000000
+#define GRC_MISC_BD_ID_5703                         0x00000000
+#define GRC_MISC_BD_ID_5703S                        0x00002000
+#define GRC_MISC_BD_ID_5702FE                       0x00004000
+#define GRC_MISC_BD_ID_5704                         0x00000000
+#define GRC_MISC_BD_ID_5704CIOBE                    0x00004000
+
+	/* Miscellaneous local control register. */
+	T3_32BIT_REGISTER LocalCtrl;
+#define GRC_MISC_LOCAL_CTRL_INT_ACTIVE              BIT_0
+#define GRC_MISC_LOCAL_CTRL_CLEAR_INT               BIT_1
+#define GRC_MISC_LOCAL_CTRL_SET_INT                 BIT_2
+#define GRC_MISC_LOCAL_CTRL_INT_ON_ATTN             BIT_3
+#define GRC_MISC_LOCAL_CTRL_GPIO_INPUT0             BIT_8
+#define GRC_MISC_LOCAL_CTRL_GPIO_INPUT1             BIT_9
+#define GRC_MISC_LOCAL_CTRL_GPIO_INPUT2             BIT_10
+#define GRC_MISC_LOCAL_CTRL_GPIO_OE0                BIT_11
+#define GRC_MISC_LOCAL_CTRL_GPIO_OE1                BIT_12
+#define GRC_MISC_LOCAL_CTRL_GPIO_OE2                BIT_13
+#define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0            BIT_14
+#define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1            BIT_15
+#define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2            BIT_16
+#define GRC_MISC_LOCAL_CTRL_ENABLE_EXT_MEMORY       BIT_17
+#define GRC_MISC_LOCAL_CTRL_BANK_SELECT             BIT_21
+#define GRC_MISC_LOCAL_CTRL_SSRAM_TYPE              BIT_22
+
+#define GRC_MISC_MEMSIZE_256K     0
+#define GRC_MISC_MEMSIZE_512K     (1 << 18)
+#define GRC_MISC_MEMSIZE_1024K    (2 << 18)
+#define GRC_MISC_MEMSIZE_2048K    (3 << 18)
+#define GRC_MISC_MEMSIZE_4096K    (4 << 18)
+#define GRC_MISC_MEMSIZE_8192K    (5 << 18)
+#define GRC_MISC_MEMSIZE_16M      (6 << 18)
+#define GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM            BIT_24
+
+	T3_32BIT_REGISTER Timer;
+
+	T3_32BIT_REGISTER RxCpuEvent;
+	T3_32BIT_REGISTER RxTimerRef;
+	T3_32BIT_REGISTER RxCpuSemaphore;
+	T3_32BIT_REGISTER RemoteRxCpuAttn;
+
+	T3_32BIT_REGISTER TxCpuEvent;
+	T3_32BIT_REGISTER TxTimerRef;
+	T3_32BIT_REGISTER TxCpuSemaphore;
+	T3_32BIT_REGISTER RemoteTxCpuAttn;
+
+	T3_64BIT_REGISTER MemoryPowerUp;
+
+	T3_32BIT_REGISTER EepromAddr;
+#define SEEPROM_ADDR_WRITE       0
+#define SEEPROM_ADDR_READ        (1 << 31)
+#define SEEPROM_ADDR_RW_MASK     0x80000000
+#define SEEPROM_ADDR_COMPLETE    (1 << 30)
+#define SEEPROM_ADDR_FSM_RESET   (1 << 29)
+#define SEEPROM_ADDR_DEV_ID(x)   (x << 26)
+#define SEEPROM_ADDR_DEV_ID_MASK 0x1c000000
+#define SEEPROM_ADDR_START       (1 << 25)
+#define SEEPROM_ADDR_CLK_PERD(x) (x << 16)
+#define SEEPROM_ADDR_ADDRESS(x)  (x & 0xfffc)
+#define SEEPROM_ADDR_ADDRESS_MASK 0x0000ffff
+
+#define SEEPROM_CLOCK_PERIOD        60
+#define SEEPROM_CHIP_SIZE           (64 * 1024)
+
+	T3_32BIT_REGISTER EepromData;
+	T3_32BIT_REGISTER EepromCtrl;
+
+	T3_32BIT_REGISTER MdiCtrl;
+	T3_32BIT_REGISTER SepromDelay;
+
+	/* Unused space. */
+	LM_UINT8 Unused[948];
+} T3_GRC, *PT3_GRC;
+
+/******************************************************************************/
+/* NVRAM control registers. */
+/******************************************************************************/
+
+typedef struct {
+	T3_32BIT_REGISTER Cmd;
+#define NVRAM_CMD_RESET                             BIT_0
+#define NVRAM_CMD_DONE                              BIT_3
+#define NVRAM_CMD_DO_IT                             BIT_4
+#define NVRAM_CMD_WR                                BIT_5
+#define NVRAM_CMD_RD                                BIT_NONE
+#define NVRAM_CMD_ERASE                             BIT_6
+#define NVRAM_CMD_FIRST                             BIT_7
+#define NVRAM_CMD_LAST                              BIT_8
+
+	T3_32BIT_REGISTER Status;
+	T3_32BIT_REGISTER WriteData;
+
+	T3_32BIT_REGISTER Addr;
+#define NVRAM_ADDRESS_MASK                          0xffffff
+
+	T3_32BIT_REGISTER ReadData;
+
+	/* Flash config 1 register. */
+	T3_32BIT_REGISTER Config1;
+#define FLASH_INTERFACE_ENABLE                      BIT_0
+#define FLASH_SSRAM_BUFFERRED_MODE                  BIT_1
+#define FLASH_PASS_THRU_MODE                        BIT_2
+#define FLASH_BIT_BANG_MODE                         BIT_3
+#define FLASH_COMPAT_BYPASS                         BIT_31
+
+	/* Buffered flash (Atmel: AT45DB011B) specific information */
+#define BUFFERED_FLASH_PAGE_POS         9
+#define BUFFERED_FLASH_BYTE_ADDR_MASK   ((1<<BUFFERED_FLASH_PAGE_POS) - 1)
+#define BUFFERED_FLASH_PAGE_SIZE        264
+#define BUFFERED_FLASH_PHY_PAGE_SIZE    512
+
+	T3_32BIT_REGISTER Config2;
+	T3_32BIT_REGISTER Config3;
+	T3_32BIT_REGISTER SwArb;
+#define SW_ARB_REQ_SET0                             BIT_0
+#define SW_ARB_REQ_SET1                             BIT_1
+#define SW_ARB_REQ_SET2                             BIT_2
+#define SW_ARB_REQ_SET3                             BIT_3
+#define SW_ARB_REQ_CLR0                             BIT_4
+#define SW_ARB_REQ_CLR1                             BIT_5
+#define SW_ARB_REQ_CLR2                             BIT_6
+#define SW_ARB_REQ_CLR3                             BIT_7
+#define SW_ARB_GNT0                                 BIT_8
+#define SW_ARB_GNT1                                 BIT_9
+#define SW_ARB_GNT2                                 BIT_10
+#define SW_ARB_GNT3                                 BIT_11
+#define SW_ARB_REQ0                                 BIT_12
+#define SW_ARB_REQ1                                 BIT_13
+#define SW_ARB_REQ2                                 BIT_14
+#define SW_ARB_REQ3                                 BIT_15
+
+	/* Unused space. */
+	LM_UINT8 Unused[988];
+} T3_NVRAM, *PT3_NVRAM;
+
+/******************************************************************************/
+/* NIC's internal memory. */
+/******************************************************************************/
+
+typedef struct {
+	/* Page zero for the internal CPUs. */
+	LM_UINT8 PageZero[0x100];	/* 0x0000 */
+
+	/* Send RCBs. */
+	T3_RCB SendRcb[16];	/* 0x0100 */
+
+	/* Receive Return RCBs. */
+	T3_RCB RcvRetRcb[16];	/* 0x0200 */
+
+	/* Statistics block. */
+	T3_STATS_BLOCK StatsBlk;	/* 0x0300 */
+
+	/* Status block. */
+	T3_STATUS_BLOCK StatusBlk;	/* 0x0b00 */
+
+	/* Reserved for software. */
+	LM_UINT8 Reserved[1200];	/* 0x0b50 */
+
+	/* Unmapped region. */
+	LM_UINT8 Unmapped[4096];	/* 0x1000 */
+
+	/* DMA descriptors. */
+	LM_UINT8 DmaDesc[8192];	/* 0x2000 */
+
+	/* Buffer descriptors. */
+	LM_UINT8 BufferDesc[16384];	/* 0x4000 */
+} T3_FIRST_32K_SRAM, *PT3_FIRST_32K_SRAM;
+
+/******************************************************************************/
+/* Memory layout. */
+/******************************************************************************/
+
+typedef struct {
+	/* PCI configuration registers. */
+	T3_PCI_CONFIGURATION PciCfg;
+
+	/* Unused. */
+	LM_UINT8 Unused1[0x100];	/* 0x0100 */
+
+	/* Mailbox . */
+	T3_MAILBOX Mailbox;	/* 0x0200 */
+
+	/* MAC control registers. */
+	T3_MAC_CONTROL MacCtrl;	/* 0x0400 */
+
+	/* Send data initiator control registers. */
+	T3_SEND_DATA_INITIATOR SndDataIn;	/* 0x0c00 */
+
+	/* Send data completion Control registers. */
+	T3_SEND_DATA_COMPLETION SndDataComp;	/* 0x1000 */
+
+	/* Send BD ring selector. */
+	T3_SEND_BD_SELECTOR SndBdSel;	/* 0x1400 */
+
+	/* Send BD initiator control registers. */
+	T3_SEND_BD_INITIATOR SndBdIn;	/* 0x1800 */
+
+	/* Send BD completion control registers. */
+	T3_SEND_BD_COMPLETION SndBdComp;	/* 0x1c00 */
+
+	/* Receive list placement control registers. */
+	T3_RCV_LIST_PLACEMENT RcvListPlmt;	/* 0x2000 */
+
+	/* Receive Data and Receive BD Initiator Control. */
+	T3_RCV_DATA_BD_INITIATOR RcvDataBdIn;	/* 0x2400 */
+
+	/* Receive Data Completion Control */
+	T3_RCV_DATA_COMPLETION RcvDataComp;	/* 0x2800 */
+
+	/* Receive BD Initiator Control Registers. */
+	T3_RCV_BD_INITIATOR RcvBdIn;	/* 0x2c00 */
+
+	/* Receive BD Completion Control Registers. */
+	T3_RCV_BD_COMPLETION RcvBdComp;	/* 0x3000 */
+
+	/* Receive list selector control registers. */
+	T3_RCV_LIST_SELECTOR RcvListSel;	/* 0x3400 */
+
+	/* Mbuf cluster free registers. */
+	T3_MBUF_CLUSTER_FREE MbufClusterFree;	/* 0x3800 */
+
+	/* Host coalescing control registers. */
+	T3_HOST_COALESCING HostCoalesce;	/* 0x3c00 */
+
+	/* Memory arbiter control registers. */
+	T3_MEM_ARBITER MemArbiter;	/* 0x4000 */
+
+	/* Buffer manger control registers. */
+	T3_BUFFER_MANAGER BufMgr;	/* 0x4400 */
+
+	/* Read DMA control registers. */
+	T3_DMA_READ DmaRead;	/* 0x4800 */
+
+	/* Write DMA control registers. */
+	T3_DMA_WRITE DmaWrite;	/* 0x4c00 */
+
+	T3_CPU rxCpu;		/* 0x5000 */
+	T3_CPU txCpu;		/* 0x5400 */
+
+	/* Mailboxes. */
+	T3_GRC_MAILBOX GrcMailbox;	/* 0x5800 */
+
+	/* Flow Through queues. */
+	T3_FTQ Ftq;		/* 0x5c00 */
+
+	/* Message signaled interrupt registes. */
+	T3_MSG_SIGNALED_INT Msi;	/* 0x6000 */
+
+	/* DMA completion registers. */
+	T3_DMA_COMPLETION DmaComp;	/* 0x6400 */
+
+	/* GRC registers. */
+	T3_GRC Grc;		/* 0x6800 */
+
+	/* Unused space. */
+	LM_UINT8 Unused2[1024];	/* 0x6c00 */
+
+	/* NVRAM registers. */
+	T3_NVRAM Nvram;		/* 0x7000 */
+
+	/* Unused space. */
+	LM_UINT8 Unused3[3072];	/* 0x7400 */
+
+	/* The 32k memory window into the NIC's */
+	/* internal memory.  The memory window is */
+	/* controlled by the Memory Window Base */
+	/* Address register.  This register is located */
+	/* in the PCI configuration space. */
+	union {			/* 0x8000 */
+		T3_FIRST_32K_SRAM First32k;
+
+		/* Use the memory window base address register to determine the */
+		/* MBUF segment. */
+		LM_UINT32 Mbuf[32768 / 4];
+		LM_UINT32 MemBlock32K[32768 / 4];
+	} uIntMem;
+} T3_STD_MEM_MAP, *PT3_STD_MEM_MAP;
+
+/******************************************************************************/
+/* Adapter info. */
+/******************************************************************************/
+
+typedef struct {
+	LM_UINT16 Svid;
+	LM_UINT16 Ssid;
+	LM_UINT32 PhyId;
+	LM_UINT32 Serdes;	/* 0 = copper PHY, 1 = Serdes */
+} LM_ADAPTER_INFO, *PLM_ADAPTER_INFO;
+
+/******************************************************************************/
+/* Packet queues. */
+/******************************************************************************/
+
+DECLARE_QUEUE_TYPE (LM_RX_PACKET_Q, MAX_RX_PACKET_DESC_COUNT);
+DECLARE_QUEUE_TYPE (LM_TX_PACKET_Q, MAX_TX_PACKET_DESC_COUNT);
+
+/******************************************************************************/
+/* Tx counters. */
+/******************************************************************************/
+
+typedef struct {
+	LM_COUNTER TxPacketGoodCnt;
+	LM_COUNTER TxBytesGoodCnt;
+	LM_COUNTER TxPacketAbortedCnt;
+	LM_COUNTER NoSendBdLeftCnt;
+	LM_COUNTER NoMapRegisterLeftCnt;
+	LM_COUNTER TooManyFragmentsCnt;
+	LM_COUNTER NoTxPacketDescCnt;
+} LM_TX_COUNTERS, *PLM_TX_COUNTERS;
+
+/******************************************************************************/
+/* Rx counters. */
+/******************************************************************************/
+
+typedef struct {
+	LM_COUNTER RxPacketGoodCnt;
+	LM_COUNTER RxBytesGoodCnt;
+	LM_COUNTER RxPacketErrCnt;
+	LM_COUNTER RxErrCrcCnt;
+	LM_COUNTER RxErrCollCnt;
+	LM_COUNTER RxErrLinkLostCnt;
+	LM_COUNTER RxErrPhyDecodeCnt;
+	LM_COUNTER RxErrOddNibbleCnt;
+	LM_COUNTER RxErrMacAbortCnt;
+	LM_COUNTER RxErrShortPacketCnt;
+	LM_COUNTER RxErrNoResourceCnt;
+	LM_COUNTER RxErrLargePacketCnt;
+} LM_RX_COUNTERS, *PLM_RX_COUNTERS;
+
+/******************************************************************************/
+/* Receive producer rings. */
+/******************************************************************************/
+
+typedef enum {
+	T3_UNKNOWN_RCV_PROD_RING = 0,
+	T3_STD_RCV_PROD_RING = 1,
+	T3_MINI_RCV_PROD_RING = 2,
+	T3_JUMBO_RCV_PROD_RING = 3
+} T3_RCV_PROD_RING, *PT3_RCV_PROD_RING;
+
+/******************************************************************************/
+/* Packet descriptor. */
+/******************************************************************************/
+
+#define LM_PACKET_SIGNATURE_TX              0x6861766b
+#define LM_PACKET_SIGNATURE_RX              0x6b766168
+
+typedef struct _LM_PACKET {
+	/* Set in LM. */
+	LM_STATUS PacketStatus;
+
+	/* Set in LM for Rx, in UM for Tx. */
+	LM_UINT32 PacketSize;
+
+	LM_UINT16 Flags;
+
+	LM_UINT16 VlanTag;
+
+	union {
+		/* Send info. */
+		struct {
+			/* Set up by UM. */
+			LM_UINT32 FragCount;
+
+		} Tx;
+
+		/* Receive info. */
+		struct {
+			/* This descriptor belongs to either Std, Mini, or Jumbo ring. */
+			T3_RCV_PROD_RING RcvProdRing;
+
+			/* Receive buffer size */
+			LM_UINT32 RxBufferSize;
+
+			/* Checksum information. */
+			LM_UINT16 IpChecksum;
+			LM_UINT16 TcpUdpChecksum;
+
+		} Rx;
+	} u;
+} LM_PACKET;
+
+/******************************************************************************/
+/* Tigon3 device block. */
+/******************************************************************************/
+
+typedef struct _LM_DEVICE_BLOCK {
+	int index;		/* Device ID */
+	/* Memory view. */
+	PT3_STD_MEM_MAP pMemView;
+
+	/* Base address of the block of memory in which the LM_PACKET descriptors */
+	/* are allocated from. */
+	PLM_VOID pPacketDescBase;
+
+	LM_UINT32 MiscHostCtrl;
+	LM_UINT32 GrcLocalCtrl;
+	LM_UINT32 DmaReadWriteCtrl;
+	LM_UINT32 PciState;
+
+	/* Rx info */
+	LM_UINT32 RxStdDescCnt;
+	LM_UINT32 RxStdQueuedCnt;
+	LM_UINT32 RxStdProdIdx;
+
+	PT3_RCV_BD pRxStdBdVirt;
+	LM_PHYSICAL_ADDRESS RxStdBdPhy;
+
+	LM_UINT32 RxPacketDescCnt;
+	LM_RX_PACKET_Q RxPacketFreeQ;
+	LM_RX_PACKET_Q RxPacketReceivedQ;
+
+	/* Receive info. */
+	PT3_RCV_BD pRcvRetBdVirt;
+	LM_PHYSICAL_ADDRESS RcvRetBdPhy;
+	LM_UINT32 RcvRetConIdx;
+
+#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
+	LM_UINT32 RxJumboDescCnt;
+	LM_UINT32 RxJumboBufferSize;
+	LM_UINT32 RxJumboQueuedCnt;
+
+	LM_UINT32 RxJumboProdIdx;
+
+	PT3_RCV_BD pRxJumboBdVirt;
+	LM_PHYSICAL_ADDRESS RxJumboBdPhy;
+#endif				/* T3_JUMBO_RCV_RCB_ENTRY_COUNT */
+
+	/* These values are used by the upper module to inform the protocol */
+	/* of the maximum transmit/receive packet size. */
+	LM_UINT32 TxMtu;	/* Does not include CRC. */
+	LM_UINT32 RxMtu;	/* Does not include CRC. */
+
+	/* We need to shadow the EMAC, Rx, Tx mode registers.  With B0 silicon, */
+	/* we may have problems reading any MAC registers in 10mb mode. */
+	LM_UINT32 MacMode;
+	LM_UINT32 RxMode;
+	LM_UINT32 TxMode;
+
+	/* MiMode register. */
+	LM_UINT32 MiMode;
+
+	/* Host coalesce mode register. */
+	LM_UINT32 CoalesceMode;
+
+	/* Send info. */
+	LM_UINT32 TxPacketDescCnt;
+
+	/* Tx info. */
+	LM_TX_PACKET_Q TxPacketFreeQ;
+	LM_TX_PACKET_Q TxPacketActiveQ;
+	LM_TX_PACKET_Q TxPacketXmittedQ;
+
+	/* Pointers to SendBd. */
+	PT3_SND_BD pSendBdVirt;
+	LM_PHYSICAL_ADDRESS SendBdPhy;	/* Only valid for Host based Send BD. */
+
+	/* Send producer and consumer indices. */
+	LM_UINT32 SendProdIdx;
+	LM_UINT32 SendConIdx;
+
+	/* Number of BD left. */
+	atomic_t SendBdLeft;
+
+	T3_SND_BD ShadowSendBd[T3_SEND_RCB_ENTRY_COUNT];
+
+	/* Counters. */
+	LM_RX_COUNTERS RxCounters;
+	LM_TX_COUNTERS TxCounters;
+
+	/* Host coalescing parameters. */
+	LM_UINT32 RxCoalescingTicks;
+	LM_UINT32 TxCoalescingTicks;
+	LM_UINT32 RxMaxCoalescedFrames;
+	LM_UINT32 TxMaxCoalescedFrames;
+	LM_UINT32 StatsCoalescingTicks;
+	LM_UINT32 RxCoalescingTicksDuringInt;
+	LM_UINT32 TxCoalescingTicksDuringInt;
+	LM_UINT32 RxMaxCoalescedFramesDuringInt;
+	LM_UINT32 TxMaxCoalescedFramesDuringInt;
+
+	/* DMA water marks. */
+	LM_UINT32 DmaMbufLowMark;
+	LM_UINT32 RxMacMbufLowMark;
+	LM_UINT32 MbufHighMark;
+
+	/* Status block. */
+	PT3_STATUS_BLOCK pStatusBlkVirt;
+	LM_PHYSICAL_ADDRESS StatusBlkPhy;
+
+	/* Statistics block. */
+	PT3_STATS_BLOCK pStatsBlkVirt;
+	LM_PHYSICAL_ADDRESS StatsBlkPhy;
+
+	/* Current receive mask. */
+	LM_UINT32 ReceiveMask;
+
+	/* Task offload capabilities. */
+	LM_TASK_OFFLOAD TaskOffloadCap;
+
+	/* Task offload selected. */
+	LM_TASK_OFFLOAD TaskToOffload;
+
+	/* Wake up capability. */
+	LM_WAKE_UP_MODE WakeUpModeCap;
+
+	/* Wake up capability. */
+	LM_WAKE_UP_MODE WakeUpMode;
+
+	/* Flow control. */
+	LM_FLOW_CONTROL FlowControlCap;
+	LM_FLOW_CONTROL FlowControl;
+
+	/* Enable or disable PCI MWI. */
+	LM_UINT32 EnableMWI;
+
+	/* Enable 5701 tagged status mode. */
+	LM_UINT32 UseTaggedStatus;
+
+	/* NIC will not compute the pseudo header checksum.  The driver or OS */
+	/* must seed the checksum field with the pseudo checksum. */
+	LM_UINT32 NoTxPseudoHdrChksum;
+
+	/* The receive checksum in the BD does not include the pseudo checksum. */
+	/* The OS or the driver must calculate the pseudo checksum and add it to */
+	/* the checksum in the BD. */
+	LM_UINT32 NoRxPseudoHdrChksum;
+
+	/* Current node address. */
+	LM_UINT8 NodeAddress[8];
+
+	/* The adapter's node address. */
+	LM_UINT8 PermanentNodeAddress[8];
+
+	/* Adapter info. */
+	LM_UINT16 BusNum;
+	LM_UINT8 DevNum;
+	LM_UINT8 FunctNum;
+	LM_UINT16 PciVendorId;
+	LM_UINT16 PciDeviceId;
+	LM_UINT32 BondId;
+	LM_UINT8 Irq;
+	LM_UINT8 IntPin;
+	LM_UINT8 CacheLineSize;
+	LM_UINT8 PciRevId;
+#if PCIX_TARGET_WORKAROUND
+	LM_UINT32 EnablePciXFix;
+#endif
+	LM_UINT32 UndiFix;	/* new, jimmy */
+	LM_UINT32 PciCommandStatusWords;
+	LM_UINT32 ChipRevId;
+	LM_UINT16 SubsystemVendorId;
+	LM_UINT16 SubsystemId;
+#if 0				/* Jimmy, deleted in new driver */
+	LM_UINT32 MemBaseLow;
+	LM_UINT32 MemBaseHigh;
+	LM_UINT32 MemBaseSize;
+#endif
+	PLM_UINT8 pMappedMemBase;
+
+	/* Saved PCI configuration registers for restoring after a reset. */
+	LM_UINT32 SavedCacheLineReg;
+
+	/* Phy info. */
+	LM_UINT32 PhyAddr;
+	LM_UINT32 PhyId;
+
+	/* Requested phy settings. */
+	LM_REQUESTED_MEDIA_TYPE RequestedMediaType;
+
+	/* Disable auto-negotiation. */
+	LM_UINT32 DisableAutoNeg;
+
+	/* Ways for the MAC to get link change interrupt. */
+	LM_UINT32 PhyIntMode;
+#define T3_PHY_INT_MODE_AUTO                        0
+#define T3_PHY_INT_MODE_MI_INTERRUPT                1
+#define T3_PHY_INT_MODE_LINK_READY                  2
+#define T3_PHY_INT_MODE_AUTO_POLLING                3
+
+	/* Ways to determine link change status. */
+	LM_UINT32 LinkChngMode;
+#define T3_LINK_CHNG_MODE_AUTO                      0
+#define T3_LINK_CHNG_MODE_USE_STATUS_REG            1
+#define T3_LINK_CHNG_MODE_USE_STATUS_BLOCK          2
+
+	/* LED mode. */
+	LM_UINT32 LedMode;
+
+#define LED_MODE_AUTO                               0
+
+	/* 5700/01 LED mode. */
+#define LED_MODE_THREE_LINK                         1
+#define LED_MODE_LINK10                             2
+
+	/* 5703/02/04 LED mode. */
+#define LED_MODE_OPEN_DRAIN                         1
+#define LED_MODE_OUTPUT                             2
+
+	/* WOL Speed */
+	LM_UINT32 WolSpeed;
+#define WOL_SPEED_10MB                              1
+#define WOL_SPEED_100MB                             2
+
+	/* Reset the PHY on initialization. */
+	LM_UINT32 ResetPhyOnInit;
+
+	LM_UINT32 RestoreOnWakeUp;
+	LM_REQUESTED_MEDIA_TYPE WakeUpRequestedMediaType;
+	LM_UINT32 WakeUpDisableAutoNeg;
+
+	/* Current phy settings. */
+	LM_MEDIA_TYPE MediaType;
+	LM_LINE_SPEED LineSpeed;
+	LM_LINE_SPEED OldLineSpeed;
+	LM_DUPLEX_MODE DuplexMode;
+	LM_STATUS LinkStatus;
+	LM_UINT32 advertising;	/* Jimmy, new! */
+	LM_UINT32 advertising1000;	/* Jimmy, new! */
+
+	/* Multicast address list. */
+	LM_UINT32 McEntryCount;
+	LM_UINT8 McTable[LM_MAX_MC_TABLE_SIZE][LM_MC_ENTRY_SIZE];
+
+	/* Use NIC or Host based send BD. */
+	LM_UINT32 NicSendBd;
+
+	/* Athlon fix. */
+	LM_UINT32 DelayPciGrant;
+
+	/* Enable OneDmaAtOnce */
+	LM_UINT32 OneDmaAtOnce;
+
+	/* Split Mode flags, Jimmy new */
+	LM_UINT32 SplitModeEnable;
+	LM_UINT32 SplitModeMaxReq;
+
+	/* Init flag. */
+	LM_BOOL InitDone;
+
+	/* Shutdown flag.  Set by the upper module. */
+	LM_BOOL ShuttingDown;
+
+	/* Flag to determine whether to call LM_QueueRxPackets or not in */
+	/* LM_ResetAdapter routine. */
+	LM_BOOL QueueRxPackets;
+
+	LM_UINT32 MbufBase;
+	LM_UINT32 MbufSize;
+
+	/* TRUE if we have a SERDES PHY. */
+	LM_UINT32 EnableTbi;
+
+	/* Ethernet@WireSpeed. */
+	LM_UINT32 EnableWireSpeed;
+
+	LM_UINT32 EepromWp;
+
+#if INCLUDE_TBI_SUPPORT
+	/* Autoneg state info. */
+	AN_STATE_INFO AnInfo;
+	LM_UINT32 PollTbiLink;
+	LM_UINT32 IgnoreTbiLinkChange;
+#endif
+	char PartNo[24];
+	char BootCodeVer[16];
+	char BusSpeedStr[24];	/* Jimmy, new! */
+	LM_UINT32 PhyCrcCount;
+} LM_DEVICE_BLOCK;
+
+#define T3_REG_CPU_VIEW               0xc0000000
+
+#define T3_BLOCK_DMA_RD               (1 << 0)
+#define T3_BLOCK_DMA_COMP             (1 << 1)
+#define T3_BLOCK_RX_BD_INITIATOR      (1 << 2)
+#define T3_BLOCK_RX_BD_COMP           (1 << 3)
+#define T3_BLOCK_DMA_WR               (1 << 4)
+#define T3_BLOCK_MSI_HANDLER          (1 << 5)
+#define T3_BLOCK_RX_LIST_PLMT         (1 << 6)
+#define T3_BLOCK_RX_LIST_SELECTOR     (1 << 7)
+#define T3_BLOCK_RX_DATA_INITIATOR    (1 << 8)
+#define T3_BLOCK_RX_DATA_COMP         (1 << 9)
+#define T3_BLOCK_HOST_COALESING       (1 << 10)
+#define T3_BLOCK_MAC_RX_ENGINE        (1 << 11)
+#define T3_BLOCK_MBUF_CLUSTER_FREE    (1 << 12)
+#define T3_BLOCK_SEND_BD_INITIATOR    (1 << 13)
+#define T3_BLOCK_SEND_BD_COMP         (1 << 14)
+#define T3_BLOCK_SEND_BD_SELECTOR     (1 << 15)
+#define T3_BLOCK_SEND_DATA_INITIATOR  (1 << 16)
+#define T3_BLOCK_SEND_DATA_COMP       (1 << 17)
+#define T3_BLOCK_MAC_TX_ENGINE        (1 << 18)
+#define T3_BLOCK_MEM_ARBITOR          (1 << 19)
+#define T3_BLOCK_MBUF_MANAGER         (1 << 20)
+#define T3_BLOCK_MAC_GLOBAL           (1 << 21)
+
+#define LM_ENABLE               1
+#define LM_DISABLE              2
+
+#define RX_CPU_EVT_SW0              0
+#define RX_CPU_EVT_SW1              1
+#define RX_CPU_EVT_RLP              2
+#define RX_CPU_EVT_SW3              3
+#define RX_CPU_EVT_RLS              4
+#define RX_CPU_EVT_SW4              5
+#define RX_CPU_EVT_RX_BD_COMP       6
+#define RX_CPU_EVT_SW5              7
+#define RX_CPU_EVT_RDI              8
+#define RX_CPU_EVT_DMA_WR           9
+#define RX_CPU_EVT_DMA_RD           10
+#define RX_CPU_EVT_SWQ              11
+#define RX_CPU_EVT_SW6              12
+#define RX_CPU_EVT_RDC              13
+#define RX_CPU_EVT_SW7              14
+#define RX_CPU_EVT_HOST_COALES      15
+#define RX_CPU_EVT_SW8              16
+#define RX_CPU_EVT_HIGH_DMA_WR      17
+#define RX_CPU_EVT_HIGH_DMA_RD      18
+#define RX_CPU_EVT_SW9              19
+#define RX_CPU_EVT_DMA_ATTN         20
+#define RX_CPU_EVT_LOW_P_MBOX       21
+#define RX_CPU_EVT_HIGH_P_MBOX      22
+#define RX_CPU_EVT_SW10             23
+#define RX_CPU_EVT_TX_CPU_ATTN      24
+#define RX_CPU_EVT_MAC_ATTN         25
+#define RX_CPU_EVT_RX_CPU_ATTN      26
+#define RX_CPU_EVT_FLOW_ATTN        27
+#define RX_CPU_EVT_SW11             28
+#define RX_CPU_EVT_TIMER            29
+#define RX_CPU_EVT_SW12             30
+#define RX_CPU_EVT_SW13             31
+
+/* RX-CPU event */
+#define RX_CPU_EVENT_SW_EVENT0      (1 << RX_CPU_EVT_SW0)
+#define RX_CPU_EVENT_SW_EVENT1      (1 << RX_CPU_EVT_SW1)
+#define RX_CPU_EVENT_RLP            (1 << RX_CPU_EVT_RLP)
+#define RX_CPU_EVENT_SW_EVENT3      (1 << RX_CPU_EVT_SW3)
+#define RX_CPU_EVENT_RLS            (1 << RX_CPU_EVT_RLS)
+#define RX_CPU_EVENT_SW_EVENT4      (1 << RX_CPU_EVT_SW4)
+#define RX_CPU_EVENT_RX_BD_COMP     (1 << RX_CPU_EVT_RX_BD_COMP)
+#define RX_CPU_EVENT_SW_EVENT5      (1 << RX_CPU_EVT_SW5)
+#define RX_CPU_EVENT_RDI            (1 << RX_CPU_EVT_RDI)
+#define RX_CPU_EVENT_DMA_WR         (1 << RX_CPU_EVT_DMA_WR)
+#define RX_CPU_EVENT_DMA_RD         (1 << RX_CPU_EVT_DMA_RD)
+#define RX_CPU_EVENT_SWQ            (1 << RX_CPU_EVT_SWQ)
+#define RX_CPU_EVENT_SW_EVENT6      (1 << RX_CPU_EVT_SW6)
+#define RX_CPU_EVENT_RDC            (1 << RX_CPU_EVT_RDC)
+#define RX_CPU_EVENT_SW_EVENT7      (1 << RX_CPU_EVT_SW7)
+#define RX_CPU_EVENT_HOST_COALES    (1 << RX_CPU_EVT_HOST_COALES)
+#define RX_CPU_EVENT_SW_EVENT8      (1 << RX_CPU_EVT_SW8)
+#define RX_CPU_EVENT_HIGH_DMA_WR    (1 << RX_CPU_EVT_HIGH_DMA_WR)
+#define RX_CPU_EVENT_HIGH_DMA_RD    (1 << RX_CPU_EVT_HIGH_DMA_RD)
+#define RX_CPU_EVENT_SW_EVENT9      (1 << RX_CPU_EVT_SW9)
+#define RX_CPU_EVENT_DMA_ATTN       (1 << RX_CPU_EVT_DMA_ATTN)
+#define RX_CPU_EVENT_LOW_P_MBOX     (1 << RX_CPU_EVT_LOW_P_MBOX)
+#define RX_CPU_EVENT_HIGH_P_MBOX    (1 << RX_CPU_EVT_HIGH_P_MBOX)
+#define RX_CPU_EVENT_SW_EVENT10     (1 << RX_CPU_EVT_SW10)
+#define RX_CPU_EVENT_TX_CPU_ATTN    (1 << RX_CPU_EVT_TX_CPU_ATTN)
+#define RX_CPU_EVENT_MAC_ATTN       (1 << RX_CPU_EVT_MAC_ATTN)
+#define RX_CPU_EVENT_RX_CPU_ATTN    (1 << RX_CPU_EVT_RX_CPU_ATTN)
+#define RX_CPU_EVENT_FLOW_ATTN      (1 << RX_CPU_EVT_FLOW_ATTN)
+#define RX_CPU_EVENT_SW_EVENT11     (1 << RX_CPU_EVT_SW11)
+#define RX_CPU_EVENT_TIMER          (1 << RX_CPU_EVT_TIMER)
+#define RX_CPU_EVENT_SW_EVENT12     (1 << RX_CPU_EVT_SW12)
+#define RX_CPU_EVENT_SW_EVENT13     (1 << RX_CPU_EVT_SW13)
+
+#define RX_CPU_MASK (RX_CPU_EVENT_SW_EVENT0 | \
+		     RX_CPU_EVENT_RLP | \
+		     RX_CPU_EVENT_RDI | \
+		     RX_CPU_EVENT_RDC)
+
+#define TX_CPU_EVT_SW0              0
+#define TX_CPU_EVT_SW1              1
+#define TX_CPU_EVT_SW2              2
+#define TX_CPU_EVT_SW3              3
+#define TX_CPU_EVT_TX_MAC           4
+#define TX_CPU_EVT_SW4              5
+#define TX_CPU_EVT_SBDC             6
+#define TX_CPU_EVT_SW5              7
+#define TX_CPU_EVT_SDI              8
+#define TX_CPU_EVT_DMA_WR           9
+#define TX_CPU_EVT_DMA_RD           10
+#define TX_CPU_EVT_SWQ              11
+#define TX_CPU_EVT_SW6              12
+#define TX_CPU_EVT_SDC              13
+#define TX_CPU_EVT_SW7              14
+#define TX_CPU_EVT_HOST_COALES      15
+#define TX_CPU_EVT_SW8              16
+#define TX_CPU_EVT_HIGH_DMA_WR      17
+#define TX_CPU_EVT_HIGH_DMA_RD      18
+#define TX_CPU_EVT_SW9              19
+#define TX_CPU_EVT_DMA_ATTN         20
+#define TX_CPU_EVT_LOW_P_MBOX       21
+#define TX_CPU_EVT_HIGH_P_MBOX      22
+#define TX_CPU_EVT_SW10             23
+#define TX_CPU_EVT_RX_CPU_ATTN      24
+#define TX_CPU_EVT_MAC_ATTN         25
+#define TX_CPU_EVT_TX_CPU_ATTN      26
+#define TX_CPU_EVT_FLOW_ATTN        27
+#define TX_CPU_EVT_SW11             28
+#define TX_CPU_EVT_TIMER            29
+#define TX_CPU_EVT_SW12             30
+#define TX_CPU_EVT_SW13             31
+
+/* TX-CPU event */
+#define TX_CPU_EVENT_SW_EVENT0      (1 << TX_CPU_EVT_SW0)
+#define TX_CPU_EVENT_SW_EVENT1      (1 << TX_CPU_EVT_SW1)
+#define TX_CPU_EVENT_SW_EVENT2      (1 << TX_CPU_EVT_SW2)
+#define TX_CPU_EVENT_SW_EVENT3      (1 << TX_CPU_EVT_SW3)
+#define TX_CPU_EVENT_TX_MAC         (1 << TX_CPU_EVT_TX_MAC)
+#define TX_CPU_EVENT_SW_EVENT4      (1 << TX_CPU_EVT_SW4)
+#define TX_CPU_EVENT_SBDC           (1 << TX_CPU_EVT_SBDC)
+#define TX_CPU_EVENT_SW_EVENT5      (1 << TX_CPU_EVT_SW5)
+#define TX_CPU_EVENT_SDI            (1 << TX_CPU_EVT_SDI)
+#define TX_CPU_EVENT_DMA_WR         (1 << TX_CPU_EVT_DMA_WR)
+#define TX_CPU_EVENT_DMA_RD         (1 << TX_CPU_EVT_DMA_RD)
+#define TX_CPU_EVENT_SWQ            (1 << TX_CPU_EVT_SWQ)
+#define TX_CPU_EVENT_SW_EVENT6      (1 << TX_CPU_EVT_SW6)
+#define TX_CPU_EVENT_SDC            (1 << TX_CPU_EVT_SDC)
+#define TX_CPU_EVENT_SW_EVENT7      (1 << TX_CPU_EVT_SW7)
+#define TX_CPU_EVENT_HOST_COALES    (1 << TX_CPU_EVT_HOST_COALES)
+#define TX_CPU_EVENT_SW_EVENT8      (1 << TX_CPU_EVT_SW8)
+#define TX_CPU_EVENT_HIGH_DMA_WR    (1 << TX_CPU_EVT_HIGH_DMA_WR)
+#define TX_CPU_EVENT_HIGH_DMA_RD    (1 << TX_CPU_EVT_HIGH_DMA_RD)
+#define TX_CPU_EVENT_SW_EVENT9      (1 << TX_CPU_EVT_SW9)
+#define TX_CPU_EVENT_DMA_ATTN       (1 << TX_CPU_EVT_DMA_ATTN)
+#define TX_CPU_EVENT_LOW_P_MBOX     (1 << TX_CPU_EVT_LOW_P_MBOX)
+#define TX_CPU_EVENT_HIGH_P_MBOX    (1 << TX_CPU_EVT_HIGH_P_MBOX)
+#define TX_CPU_EVENT_SW_EVENT10     (1 << TX_CPU_EVT_SW10)
+#define TX_CPU_EVENT_RX_CPU_ATTN    (1 << TX_CPU_EVT_RX_CPU_ATTN)
+#define TX_CPU_EVENT_MAC_ATTN       (1 << TX_CPU_EVT_MAC_ATTN)
+#define TX_CPU_EVENT_TX_CPU_ATTN    (1 << TX_CPU_EVT_TX_CPU_ATTN)
+#define TX_CPU_EVENT_FLOW_ATTN      (1 << TX_CPU_EVT_FLOW_ATTN)
+#define TX_CPU_EVENT_SW_EVENT11     (1 << TX_CPU_EVT_SW11)
+#define TX_CPU_EVENT_TIMER          (1 << TX_CPU_EVT_TIMER)
+#define TX_CPU_EVENT_SW_EVENT12     (1 << TX_CPU_EVT_SW12)
+#define TX_CPU_EVENT_SW_EVENT13     (1 << TX_CPU_EVT_SW13)
+
+#define TX_CPU_MASK (TX_CPU_EVENT_SW_EVENT0 | \
+		     TX_CPU_EVENT_SDI  | \
+		     TX_CPU_EVENT_SDC)
+
+#define T3_FTQ_TYPE1_UNDERFLOW_BIT   (1 << 29)
+#define T3_FTQ_TYPE1_PASS_BIT        (1 << 30)
+#define T3_FTQ_TYPE1_SKIP_BIT        (1 << 31)
+
+#define T3_FTQ_TYPE2_UNDERFLOW_BIT   (1 << 13)
+#define T3_FTQ_TYPE2_PASS_BIT        (1 << 14)
+#define T3_FTQ_TYPE2_SKIP_BIT        (1 << 15)
+
+#define T3_QID_DMA_READ               1
+#define T3_QID_DMA_HIGH_PRI_READ      2
+#define T3_QID_DMA_COMP_DX            3
+#define T3_QID_SEND_BD_COMP           4
+#define T3_QID_SEND_DATA_INITIATOR    5
+#define T3_QID_DMA_WRITE              6
+#define T3_QID_DMA_HIGH_PRI_WRITE     7
+#define T3_QID_SW_TYPE_1              8
+#define T3_QID_SEND_DATA_COMP         9
+#define T3_QID_HOST_COALESCING        10
+#define T3_QID_MAC_TX                 11
+#define T3_QID_MBUF_CLUSTER_FREE      12
+#define T3_QID_RX_BD_COMP             13
+#define T3_QID_RX_LIST_PLM            14
+#define T3_QID_RX_DATA_BD_INITIATOR   15
+#define T3_QID_RX_DATA_COMP           16
+#define T3_QID_SW_TYPE2               17
+
+LM_STATUS LM_LoadFirmware (PLM_DEVICE_BLOCK pDevice,
+			   PT3_FWIMG_INFO pFwImg,
+			   LM_UINT32 LoadCpu, LM_UINT32 StartCpu);
+
+/******************************************************************************/
+/* NIC register read/write macros. */
+/******************************************************************************/
+
+#if 0				/* Jimmy */
+/* MAC register access. */
+LM_UINT32 LM_RegRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register);
+LM_VOID LM_RegWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register,
+		     LM_UINT32 Value32);
+
+/* MAC memory access. */
+LM_UINT32 LM_MemRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr);
+LM_VOID LM_MemWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr,
+		     LM_UINT32 Value32);
+
+#if PCIX_TARGET_WORKAROUND
+
+/* use memory-mapped accesses for mailboxes and reads, UNDI accesses
+   for writes to all other registers */
+#define REG_RD(pDevice, OffsetName)                              \
+    readl(&((pDevice)->pMemView->OffsetName))
+
+#define REG_WR(pDevice, OffsetName, Value32)                     \
+    (((OFFSETOF(T3_STD_MEM_MAP, OffsetName) >=0x200 ) &&         \
+      (OFFSETOF(T3_STD_MEM_MAP, OffsetName) <0x400)) ||	         \
+	 ((pDevice)->EnablePciXFix == FALSE)) ?                  \
+    (void) writel(Value32, &((pDevice)->pMemView->OffsetName)) : \
+    LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32)
+
+#define MB_REG_RD(pDevice, OffsetName)                           \
+    readl(&((pDevice)->pMemView->OffsetName))
+
+#define MB_REG_WR(pDevice, OffsetName, Value32)                  \
+    writel(Value32, &((pDevice)->pMemView->OffsetName))
+
+#define REG_RD_OFFSET(pDevice, Offset)                           \
+    readl(&((LM_UINT8 *) (pDevice)->pMemView + Offset))
+
+#define REG_WR_OFFSET(pDevice, Offset, Value32)                  \
+	(((Offset >=0x200 ) && (Offset < 0x400)) ||		 \
+	 ((pDevice)->EnablePciXFix == FALSE)) ?	   		 \
+    (void) writel(Value32, ((LM_UINT8 *) (pDevice)->pMemView + Offset)) : \
+    LM_RegWrInd(pDevice, Offset, Value32)
+
+#define MEM_RD(pDevice, AddrName)                                \
+    LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName))
+#define MEM_WR(pDevice, AddrName, Value32)                       \
+    LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32)
+
+#define MEM_RD_OFFSET(pDevice, Offset)                           \
+    LM_MemRdInd(pDevice, Offset)
+#define MEM_WR_OFFSET(pDevice, Offset, Value32)                  \
+    LM_MemWrInd(pDevice, Offset, Value32)
+
+#else				/* normal target access path below */
+
+/* Register access. */
+#define REG_RD(pDevice, OffsetName)                                         \
+    readl(&((pDevice)->pMemView->OffsetName))
+#define REG_WR(pDevice, OffsetName, Value32)                                \
+    writel(Value32, &((pDevice)->pMemView->OffsetName))
+
+#define REG_RD_OFFSET(pDevice, Offset)                                      \
+    readl(((LM_UINT8 *) (pDevice)->pMemView + Offset))
+#define REG_WR_OFFSET(pDevice, Offset, Value32)                             \
+    writel(Value32, ((LM_UINT8 *) (pDevice)->pMemView + Offset))
+
+/* There could be problem access the memory window directly.  For now, */
+/* we have to go through the PCI configuration register. */
+#define MEM_RD(pDevice, AddrName)                                           \
+    LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName))
+#define MEM_WR(pDevice, AddrName, Value32)                                  \
+    LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32)
+
+#define MEM_RD_OFFSET(pDevice, Offset)                                      \
+    LM_MemRdInd(pDevice, Offset)
+#define MEM_WR_OFFSET(pDevice, Offset, Value32)                             \
+    LM_MemWrInd(pDevice, Offset, Value32)
+
+#endif				/* PCIX_TARGET_WORKAROUND */
+
+#endif				/* Jimmy, merging */
+
+  /* Jimmy...rest of file is new stuff! */
+/******************************************************************************/
+/* NIC register read/write macros. */
+/******************************************************************************/
+
+/* MAC register access. */
+LM_UINT32 LM_RegRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register);
+LM_VOID LM_RegWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register,
+		     LM_UINT32 Value32);
+
+/* MAC memory access. */
+LM_UINT32 LM_MemRdInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr);
+LM_VOID LM_MemWrInd (PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr,
+		     LM_UINT32 Value32);
+
+#define MB_REG_WR(pDevice, OffsetName, Value32)                               \
+    ((pDevice)->UndiFix) ?                                                    \
+	LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600,     \
+	    Value32) :                                                        \
+	(void) __raw_writel(Value32, &((pDevice)->pMemView->OffsetName))
+
+#define MB_REG_RD(pDevice, OffsetName)                                        \
+    (((pDevice)->UndiFix) ?                                                   \
+	LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600) :   \
+	__raw_readl(&((pDevice)->pMemView->OffsetName)))
+
+#define REG_RD(pDevice, OffsetName)                                           \
+    (((pDevice)->UndiFix) ?                                                   \
+	LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)) :          \
+	__raw_readl(&((pDevice)->pMemView->OffsetName)))
+
+#if PCIX_TARGET_WORKAROUND
+
+#define REG_WR(pDevice, OffsetName, Value32)                                \
+	 ((pDevice)->EnablePciXFix == FALSE) ?                              \
+    (void) __raw_writel(Value32, &((pDevice)->pMemView->OffsetName)) :      \
+    LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32)
+
+#else
+
+#define REG_WR(pDevice, OffsetName, Value32)                                \
+    __raw_writel(Value32, &((pDevice)->pMemView->OffsetName))
+
+#endif
+
+#define MEM_RD(pDevice, AddrName)                                           \
+    LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName))
+#define MEM_WR(pDevice, AddrName, Value32)                                  \
+    LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32)
+
+#define MEM_RD_OFFSET(pDevice, Offset)                                      \
+    LM_MemRdInd(pDevice, Offset)
+#define MEM_WR_OFFSET(pDevice, Offset, Value32)                             \
+    LM_MemWrInd(pDevice, Offset, Value32)
+
+#endif				/* TIGON3_H */
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
new file mode 100644
index 0000000..ca6284b
--- /dev/null
+++ b/drivers/net/tsec.c
@@ -0,0 +1,1590 @@
+/*
+ * Freescale Three Speed Ethernet Controller driver
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2004, 2007 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * author Andy Fleming
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+
+#if defined(CONFIG_TSEC_ENET)
+#include "tsec.h"
+#include "miiphy.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TX_BUF_CNT		2
+
+static uint rxIdx;		/* index of the current RX buffer */
+static uint txIdx;		/* index of the current TX buffer */
+
+typedef volatile struct rtxbd {
+	txbd8_t txbd[TX_BUF_CNT];
+	rxbd8_t rxbd[PKTBUFSRX];
+} RTXBD;
+
+struct tsec_info_struct {
+	unsigned int phyaddr;
+	u32 flags;
+	unsigned int phyregidx;
+};
+
+/* The tsec_info structure contains 3 values which the
+ * driver uses to determine how to operate a given ethernet
+ * device. The information needed is:
+ *  phyaddr - The address of the PHY which is attached to
+ *	the given device.
+ *
+ *  flags - This variable indicates whether the device
+ *	supports gigabit speed ethernet, and whether it should be
+ *	in reduced mode.
+ *
+ *  phyregidx - This variable specifies which ethernet device
+ *	controls the MII Management registers which are connected
+ *	to the PHY.  For now, only TSEC1 (index 0) has
+ *	access to the PHYs, so all of the entries have "0".
+ *
+ * The values specified in the table are taken from the board's
+ * config file in include/configs/.  When implementing a new
+ * board with ethernet capability, it is necessary to define:
+ *   TSECn_PHY_ADDR
+ *   TSECn_PHYIDX
+ *
+ * for n = 1,2,3, etc.  And for FEC:
+ *   FEC_PHY_ADDR
+ *   FEC_PHYIDX
+ */
+static struct tsec_info_struct tsec_info[] = {
+#ifdef CONFIG_TSEC1
+	{TSEC1_PHY_ADDR, TSEC1_FLAGS, TSEC1_PHYIDX},
+#else
+	{0, 0, 0},
+#endif
+#ifdef CONFIG_TSEC2
+	{TSEC2_PHY_ADDR, TSEC2_FLAGS, TSEC2_PHYIDX},
+#else
+	{0, 0, 0},
+#endif
+#ifdef CONFIG_MPC85XX_FEC
+	{FEC_PHY_ADDR, FEC_FLAGS, FEC_PHYIDX},
+#else
+#ifdef CONFIG_TSEC3
+	{TSEC3_PHY_ADDR, TSEC3_FLAGS, TSEC3_PHYIDX},
+#else
+	{0, 0, 0},
+#endif
+#ifdef CONFIG_TSEC4
+	{TSEC4_PHY_ADDR, TSEC4_FLAGS, TSEC4_PHYIDX},
+#else
+	{0, 0, 0},
+#endif	/* CONFIG_TSEC4 */
+#endif	/* CONFIG_MPC85XX_FEC */
+};
+
+#define MAXCONTROLLERS	(4)
+
+static int relocated = 0;
+
+static struct tsec_private *privlist[MAXCONTROLLERS];
+
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+static int tsec_send(struct eth_device *dev,
+		     volatile void *packet, int length);
+static int tsec_recv(struct eth_device *dev);
+static int tsec_init(struct eth_device *dev, bd_t * bd);
+static void tsec_halt(struct eth_device *dev);
+static void init_registers(volatile tsec_t * regs);
+static void startup_tsec(struct eth_device *dev);
+static int init_phy(struct eth_device *dev);
+void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
+uint read_phy_reg(struct tsec_private *priv, uint regnum);
+struct phy_info *get_phy_info(struct eth_device *dev);
+void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
+static void adjust_link(struct eth_device *dev);
+static void relocate_cmds(void);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+static int tsec_miiphy_write(char *devname, unsigned char addr,
+			     unsigned char reg, unsigned short value);
+static int tsec_miiphy_read(char *devname, unsigned char addr,
+			    unsigned char reg, unsigned short *value);
+#endif
+#ifdef CONFIG_MCAST_TFTP
+static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
+#endif
+
+/* Initialize device structure. Returns success if PHY
+ * initialization succeeded (i.e. if it recognizes the PHY)
+ */
+int tsec_initialize(bd_t * bis, int index, char *devname)
+{
+	struct eth_device *dev;
+	int i;
+	struct tsec_private *priv;
+
+	dev = (struct eth_device *)malloc(sizeof *dev);
+
+	if (NULL == dev)
+		return 0;
+
+	memset(dev, 0, sizeof *dev);
+
+	priv = (struct tsec_private *)malloc(sizeof(*priv));
+
+	if (NULL == priv)
+		return 0;
+
+	privlist[index] = priv;
+	priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index * TSEC_SIZE);
+	priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
+					    tsec_info[index].phyregidx *
+					    TSEC_SIZE);
+
+	priv->phyaddr = tsec_info[index].phyaddr;
+	priv->flags = tsec_info[index].flags;
+
+	sprintf(dev->name, devname);
+	dev->iobase = 0;
+	dev->priv = priv;
+	dev->init = tsec_init;
+	dev->halt = tsec_halt;
+	dev->send = tsec_send;
+	dev->recv = tsec_recv;
+#ifdef CONFIG_MCAST_TFTP
+	dev->mcast = tsec_mcast_addr;
+#endif
+
+	/* Tell u-boot to get the addr from the env */
+	for (i = 0; i < 6; i++)
+		dev->enetaddr[i] = 0;
+
+	eth_register(dev);
+
+	/* Reset the MAC */
+	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
+	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
+#endif
+
+	/* Try to initialize PHY here, and return */
+	return init_phy(dev);
+}
+
+/* Initializes data structures and registers for the controller,
+ * and brings the interface up.	 Returns the link status, meaning
+ * that it returns success if the link is up, failure otherwise.
+ * This allows u-boot to find the first active controller.
+ */
+int tsec_init(struct eth_device *dev, bd_t * bd)
+{
+	uint tempval;
+	char tmpbuf[MAC_ADDR_LEN];
+	int i;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	/* Make sure the controller is stopped */
+	tsec_halt(dev);
+
+	/* Init MACCFG2.  Defaults to GMII */
+	regs->maccfg2 = MACCFG2_INIT_SETTINGS;
+
+	/* Init ECNTRL */
+	regs->ecntrl = ECNTRL_INIT_SETTINGS;
+
+	/* Copy the station address into the address registers.
+	 * Backwards, because little endian MACS are dumb */
+	for (i = 0; i < MAC_ADDR_LEN; i++) {
+		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
+	}
+	regs->macstnaddr1 = *((uint *) (tmpbuf));
+
+	tempval = *((uint *) (tmpbuf + 4));
+
+	regs->macstnaddr2 = tempval;
+
+	/* reset the indices to zero */
+	rxIdx = 0;
+	txIdx = 0;
+
+	/* Clear out (for the most part) the other registers */
+	init_registers(regs);
+
+	/* Ready the device for tx/rx */
+	startup_tsec(dev);
+
+	/* If there's no link, fail */
+	return priv->link;
+
+}
+
+/* Write value to the device's PHY through the registers
+ * specified in priv, modifying the register specified in regnum.
+ * It will wait for the write to be done (or for a timeout to
+ * expire) before exiting
+ */
+void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
+{
+	volatile tsec_t *regbase = priv->phyregs;
+	uint phyid = priv->phyaddr;
+	int timeout = 1000000;
+
+	regbase->miimadd = (phyid << 8) | regnum;
+	regbase->miimcon = value;
+	asm("sync");
+
+	timeout = 1000000;
+	while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
+}
+
+/* Reads register regnum on the device's PHY through the
+ * registers specified in priv.	 It lowers and raises the read
+ * command, and waits for the data to become valid (miimind
+ * notvalid bit cleared), and the bus to cease activity (miimind
+ * busy bit cleared), and then returns the value
+ */
+uint read_phy_reg(struct tsec_private *priv, uint regnum)
+{
+	uint value;
+	volatile tsec_t *regbase = priv->phyregs;
+	uint phyid = priv->phyaddr;
+
+	/* Put the address of the phy, and the register
+	 * number into MIIMADD */
+	regbase->miimadd = (phyid << 8) | regnum;
+
+	/* Clear the command register, and wait */
+	regbase->miimcom = 0;
+	asm("sync");
+
+	/* Initiate a read command, and wait */
+	regbase->miimcom = MIIM_READ_COMMAND;
+	asm("sync");
+
+	/* Wait for the the indication that the read is done */
+	while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
+
+	/* Grab the value read from the PHY */
+	value = regbase->miimstat;
+
+	return value;
+}
+
+/* Discover which PHY is attached to the device, and configure it
+ * properly.  If the PHY is not recognized, then return 0
+ * (failure).  Otherwise, return 1
+ */
+static int init_phy(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct phy_info *curphy;
+	volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
+
+	/* Assign a Physical address to the TBI */
+	regs->tbipa = CFG_TBIPA_VALUE;
+	regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
+	regs->tbipa = CFG_TBIPA_VALUE;
+	asm("sync");
+
+	/* Reset MII (due to new addresses) */
+	priv->phyregs->miimcfg = MIIMCFG_RESET;
+	asm("sync");
+	priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
+	asm("sync");
+	while (priv->phyregs->miimind & MIIMIND_BUSY) ;
+
+	if (0 == relocated)
+		relocate_cmds();
+
+	/* Get the cmd structure corresponding to the attached
+	 * PHY */
+	curphy = get_phy_info(dev);
+
+	if (curphy == NULL) {
+		priv->phyinfo = NULL;
+		printf("%s: No PHY found\n", dev->name);
+
+		return 0;
+	}
+
+	priv->phyinfo = curphy;
+
+	phy_run_commands(priv, priv->phyinfo->config);
+
+	return 1;
+}
+
+/*
+ * Returns which value to write to the control register.
+ * For 10/100, the value is slightly different
+ */
+uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
+{
+	if (priv->flags & TSEC_GIGABIT)
+		return MIIM_CONTROL_INIT;
+	else
+		return MIIM_CR_INIT;
+}
+
+/* Parse the status register for link, and then do
+ * auto-negotiation
+ */
+uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
+{
+	/*
+	 * Wait if the link is up, and autonegotiation is in progress
+	 * (ie - we're capable and it's not done)
+	 */
+	mii_reg = read_phy_reg(priv, MIIM_STATUS);
+	if ((mii_reg & MIIM_STATUS_LINK) && (mii_reg & PHY_BMSR_AUTN_ABLE)
+	    && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
+		int i = 0;
+
+		puts("Waiting for PHY auto negotiation to complete");
+		while (!(mii_reg & PHY_BMSR_AUTN_COMP)) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts(" TIMEOUT !\n");
+				priv->link = 0;
+				return 0;
+			}
+
+			if ((i++ % 1000) == 0) {
+				putc('.');
+			}
+			udelay(1000);	/* 1 ms */
+			mii_reg = read_phy_reg(priv, MIIM_STATUS);
+		}
+		puts(" done\n");
+		priv->link = 1;
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (mii_reg & MIIM_STATUS_LINK)
+			priv->link = 1;
+		else
+			priv->link = 0;
+	}
+
+	return 0;
+}
+
+/* Generic function which updates the speed and duplex.  If
+ * autonegotiation is enabled, it uses the AND of the link
+ * partner's advertised capabilities and our advertised
+ * capabilities.  If autonegotiation is disabled, we use the
+ * appropriate bits in the control register.
+ *
+ * Stolen from Linux's mii.c and phy_device.c
+ */
+uint mii_parse_link(uint mii_reg, struct tsec_private *priv)
+{
+	/* We're using autonegotiation */
+	if (mii_reg & PHY_BMSR_AUTN_ABLE) {
+		uint lpa = 0;
+		uint gblpa = 0;
+
+		/* Check for gigabit capability */
+		if (mii_reg & PHY_BMSR_EXT) {
+			/* We want a list of states supported by
+			 * both PHYs in the link
+			 */
+			gblpa = read_phy_reg(priv, PHY_1000BTSR);
+			gblpa &= read_phy_reg(priv, PHY_1000BTCR) << 2;
+		}
+
+		/* Set the baseline so we only have to set them
+		 * if they're different
+		 */
+		priv->speed = 10;
+		priv->duplexity = 0;
+
+		/* Check the gigabit fields */
+		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
+			priv->speed = 1000;
+
+			if (gblpa & PHY_1000BTSR_1000FD)
+				priv->duplexity = 1;
+
+			/* We're done! */
+			return 0;
+		}
+
+		lpa = read_phy_reg(priv, PHY_ANAR);
+		lpa &= read_phy_reg(priv, PHY_ANLPAR);
+
+		if (lpa & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) {
+			priv->speed = 100;
+
+			if (lpa & PHY_ANLPAR_TXFD)
+				priv->duplexity = 1;
+
+		} else if (lpa & PHY_ANLPAR_10FD)
+			priv->duplexity = 1;
+	} else {
+		uint bmcr = read_phy_reg(priv, PHY_BMCR);
+
+		priv->speed = 10;
+		priv->duplexity = 0;
+
+		if (bmcr & PHY_BMCR_DPLX)
+			priv->duplexity = 1;
+
+		if (bmcr & PHY_BMCR_1000_MBPS)
+			priv->speed = 1000;
+		else if (bmcr & PHY_BMCR_100_MBPS)
+			priv->speed = 100;
+	}
+
+	return 0;
+}
+
+/*
+ * Parse the BCM54xx status register for speed and duplex information.
+ * The linux sungem_phy has this information, but in a table format.
+ */
+uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
+{
+
+	switch((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT){
+
+		case 1:
+			printf("Enet starting in 10BT/HD\n");
+			priv->duplexity = 0;
+			priv->speed = 10;
+			break;
+
+		case 2:
+			printf("Enet starting in 10BT/FD\n");
+			priv->duplexity = 1;
+			priv->speed = 10;
+			break;
+
+		case 3:
+			printf("Enet starting in 100BT/HD\n");
+			priv->duplexity = 0;
+			priv->speed = 100;
+			break;
+
+		case 5:
+			printf("Enet starting in 100BT/FD\n");
+			priv->duplexity = 1;
+			priv->speed = 100;
+			break;
+
+		case 6:
+			printf("Enet starting in 1000BT/HD\n");
+			priv->duplexity = 0;
+			priv->speed = 1000;
+			break;
+
+		case 7:
+			printf("Enet starting in 1000BT/FD\n");
+			priv->duplexity = 1;
+			priv->speed = 1000;
+			break;
+
+		default:
+			printf("Auto-neg error, defaulting to 10BT/HD\n");
+			priv->duplexity = 0;
+			priv->speed = 10;
+			break;
+	}
+
+	return 0;
+
+}
+/* Parse the 88E1011's status register for speed and duplex
+ * information
+ */
+uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
+{
+	uint speed;
+
+	mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
+
+	if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
+		!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+		int i = 0;
+
+		puts("Waiting for PHY realtime link");
+		while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+			/* Timeout reached ? */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts(" TIMEOUT !\n");
+				priv->link = 0;
+				break;
+			}
+
+			if ((i++ % 1000) == 0) {
+				putc('.');
+			}
+			udelay(1000);	/* 1 ms */
+			mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
+		}
+		puts(" done\n");
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
+			priv->link = 1;
+		else
+			priv->link = 0;
+	}
+
+	if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
+
+	switch (speed) {
+	case MIIM_88E1011_PHYSTAT_GBIT:
+		priv->speed = 1000;
+		break;
+	case MIIM_88E1011_PHYSTAT_100:
+		priv->speed = 100;
+		break;
+	default:
+		priv->speed = 10;
+	}
+
+	return 0;
+}
+
+/* Parse the cis8201's status register for speed and duplex
+ * information
+ */
+uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
+{
+	uint speed;
+
+	if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
+	switch (speed) {
+	case MIIM_CIS8201_AUXCONSTAT_GBIT:
+		priv->speed = 1000;
+		break;
+	case MIIM_CIS8201_AUXCONSTAT_100:
+		priv->speed = 100;
+		break;
+	default:
+		priv->speed = 10;
+		break;
+	}
+
+	return 0;
+}
+
+/* Parse the vsc8244's status register for speed and duplex
+ * information
+ */
+uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
+{
+	uint speed;
+
+	if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
+	switch (speed) {
+	case MIIM_VSC8244_AUXCONSTAT_GBIT:
+		priv->speed = 1000;
+		break;
+	case MIIM_VSC8244_AUXCONSTAT_100:
+		priv->speed = 100;
+		break;
+	default:
+		priv->speed = 10;
+		break;
+	}
+
+	return 0;
+}
+
+/* Parse the DM9161's status register for speed and duplex
+ * information
+ */
+uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
+{
+	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
+		priv->speed = 100;
+	else
+		priv->speed = 10;
+
+	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	return 0;
+}
+
+/*
+ * Hack to write all 4 PHYs with the LED values
+ */
+uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
+{
+	uint phyid;
+	volatile tsec_t *regbase = priv->phyregs;
+	int timeout = 1000000;
+
+	for (phyid = 0; phyid < 4; phyid++) {
+		regbase->miimadd = (phyid << 8) | mii_reg;
+		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
+		asm("sync");
+
+		timeout = 1000000;
+		while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
+	}
+
+	return MIIM_CIS8204_SLEDCON_INIT;
+}
+
+uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv)
+{
+	if (priv->flags & TSEC_REDUCED)
+		return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
+	else
+		return MIIM_CIS8204_EPHYCON_INIT;
+}
+
+/* Initialized required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void init_registers(volatile tsec_t * regs)
+{
+	/* Clear IEVENT */
+	regs->ievent = IEVENT_INIT_CLEAR;
+
+	regs->imask = IMASK_INIT_CLEAR;
+
+	regs->hash.iaddr0 = 0;
+	regs->hash.iaddr1 = 0;
+	regs->hash.iaddr2 = 0;
+	regs->hash.iaddr3 = 0;
+	regs->hash.iaddr4 = 0;
+	regs->hash.iaddr5 = 0;
+	regs->hash.iaddr6 = 0;
+	regs->hash.iaddr7 = 0;
+
+	regs->hash.gaddr0 = 0;
+	regs->hash.gaddr1 = 0;
+	regs->hash.gaddr2 = 0;
+	regs->hash.gaddr3 = 0;
+	regs->hash.gaddr4 = 0;
+	regs->hash.gaddr5 = 0;
+	regs->hash.gaddr6 = 0;
+	regs->hash.gaddr7 = 0;
+
+	regs->rctrl = 0x00000000;
+
+	/* Init RMON mib registers */
+	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
+
+	regs->rmon.cam1 = 0xffffffff;
+	regs->rmon.cam2 = 0xffffffff;
+
+	regs->mrblr = MRBLR_INIT_SETTINGS;
+
+	regs->minflr = MINFLR_INIT_SETTINGS;
+
+	regs->attr = ATTR_INIT_SETTINGS;
+	regs->attreli = ATTRELI_INIT_SETTINGS;
+
+}
+
+/* Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void adjust_link(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	if (priv->link) {
+		if (priv->duplexity != 0)
+			regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
+		else
+			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);
+
+		switch (priv->speed) {
+		case 1000:
+			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
+					 | MACCFG2_GMII);
+			break;
+		case 100:
+		case 10:
+			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
+					 | MACCFG2_MII);
+
+			/* Set R100 bit in all modes although
+			 * it is only used in RGMII mode
+			 */
+			if (priv->speed == 100)
+				regs->ecntrl |= ECNTRL_R100;
+			else
+				regs->ecntrl &= ~(ECNTRL_R100);
+			break;
+		default:
+			printf("%s: Speed was bad\n", dev->name);
+			break;
+		}
+
+		printf("Speed: %d, %s duplex\n", priv->speed,
+		       (priv->duplexity) ? "full" : "half");
+
+	} else {
+		printf("%s: No link.\n", dev->name);
+	}
+}
+
+/* Set up the buffers and their descriptors, and bring up the
+ * interface
+ */
+static void startup_tsec(struct eth_device *dev)
+{
+	int i;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	/* Point to the buffer descriptors */
+	regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
+	regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+
+	/* Initialize the Rx Buffer descriptors */
+	for (i = 0; i < PKTBUFSRX; i++) {
+		rtx.rxbd[i].status = RXBD_EMPTY;
+		rtx.rxbd[i].length = 0;
+		rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
+	}
+	rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
+
+	/* Initialize the TX Buffer Descriptors */
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		rtx.txbd[i].status = 0;
+		rtx.txbd[i].length = 0;
+		rtx.txbd[i].bufPtr = 0;
+	}
+	rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
+
+	/* Start up the PHY */
+	if(priv->phyinfo)
+		phy_run_commands(priv, priv->phyinfo->startup);
+
+	adjust_link(dev);
+
+	/* Enable Transmit and Receive */
+	regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+
+	/* Tell the DMA it is clear to go */
+	regs->dmactrl |= DMACTRL_INIT_SETTINGS;
+	regs->tstat = TSTAT_CLEAR_THALT;
+	regs->rstat = RSTAT_CLEAR_RHALT;
+	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
+}
+
+/* This returns the status bits of the device.	The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same.	 Presumably, this would be zero if there were no
+ * errors
+ */
+static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	int i;
+	int result = 0;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	/* Find an empty buffer descriptor */
+	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx buffers full\n", dev->name);
+			return result;
+		}
+	}
+
+	rtx.txbd[txIdx].bufPtr = (uint) packet;
+	rtx.txbd[txIdx].length = length;
+	rtx.txbd[txIdx].status |=
+	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
+
+	/* Tell the DMA to go */
+	regs->tstat = TSTAT_CLEAR_THALT;
+
+	/* Wait for buffer to be transmitted */
+	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx error\n", dev->name);
+			return result;
+		}
+	}
+
+	txIdx = (txIdx + 1) % TX_BUF_CNT;
+	result = rtx.txbd[txIdx].status & TXBD_STATS;
+
+	return result;
+}
+
+static int tsec_recv(struct eth_device *dev)
+{
+	int length;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
+
+		length = rtx.rxbd[rxIdx].length;
+
+		/* Send the packet up if there were no errors */
+		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
+			NetReceive(NetRxPackets[rxIdx], length - 4);
+		} else {
+			printf("Got error %x\n",
+			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
+		}
+
+		rtx.rxbd[rxIdx].length = 0;
+
+		/* Set the wrap bit if this is the last element in the list */
+		rtx.rxbd[rxIdx].status =
+		    RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
+
+		rxIdx = (rxIdx + 1) % PKTBUFSRX;
+	}
+
+	if (regs->ievent & IEVENT_BSY) {
+		regs->ievent = IEVENT_BSY;
+		regs->rstat = RSTAT_CLEAR_RHALT;
+	}
+
+	return -1;
+
+}
+
+/* Stop the interface */
+static void tsec_halt(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	volatile tsec_t *regs = priv->regs;
+
+	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
+	regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
+
+	while (!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))) ;
+
+	regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+	/* Shut down the PHY, as needed */
+	if(priv->phyinfo)
+		phy_run_commands(priv, priv->phyinfo->shutdown);
+}
+
+struct phy_info phy_info_M88E1149S = {
+	0x1410ca,
+	"Marvell 88E1149S",
+	4,
+	(struct phy_cmd[]){     /* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{0x1d, 0x1f, NULL},
+		{0x1e, 0x200c, NULL},
+		{0x1d, 0x5, NULL},
+		{0x1e, 0x0, NULL},
+		{0x1e, 0x100, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){     /* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_88E1011_PHY_STATUS, miim_read,
+		 &mii_parse_88E1011_psr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){     /* shutdown */
+		{miim_end,}
+	},
+};
+
+/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
+struct phy_info phy_info_BCM5461S = {
+	0x02060c1,	/* 5461 ID */
+	"Broadcom BCM5461S",
+	0, /* not clear to me what minor revisions we can shift away */
+	(struct phy_cmd[]) { /* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* shutdown */
+		{miim_end,}
+	},
+};
+
+struct phy_info phy_info_BCM5464S = {
+	0x02060b1,	/* 5464 ID */
+	"Broadcom BCM5464S",
+	0, /* not clear to me what minor revisions we can shift away */
+	(struct phy_cmd[]) { /* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* shutdown */
+		{miim_end,}
+	},
+};
+
+struct phy_info phy_info_M88E1011S = {
+	0x01410c6,
+	"Marvell 88E1011S",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Reset and configure the PHY */
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   {0x1d, 0x1f, NULL},
+			   {0x1e, 0x200c, NULL},
+			   {0x1d, 0x5, NULL},
+			   {0x1e, 0x0, NULL},
+			   {0x1e, 0x100, NULL},
+			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Status is read once to clear old link state */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_88E1011_PHY_STATUS, miim_read,
+			    &mii_parse_88E1011_psr},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+struct phy_info phy_info_M88E1111S = {
+	0x01410cc,
+	"Marvell 88E1111S",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Reset and configure the PHY */
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
+			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Status is read once to clear old link state */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_88E1011_PHY_STATUS, miim_read,
+			    &mii_parse_88E1011_psr},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
+{
+	uint mii_data = read_phy_reg(priv, mii_reg);
+
+	/* Setting MIIM_88E1145_PHY_EXT_CR */
+	if (priv->flags & TSEC_REDUCED)
+		return mii_data |
+		    MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY;
+	else
+		return mii_data;
+}
+
+static struct phy_info phy_info_M88E1145 = {
+	0x01410cd,
+	"Marvell 88E1145",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Reset the PHY */
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+
+			   /* Errata E0, E1 */
+			   {29, 0x001b, NULL},
+			   {30, 0x418f, NULL},
+			   {29, 0x0016, NULL},
+			   {30, 0xa2da, NULL},
+
+			   /* Configure the PHY */
+			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+			   {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO,
+			    NULL},
+			   {MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode},
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, NULL},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Status is read once to clear old link state */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   {MIIM_88E1111_PHY_LED_CONTROL,
+			    MIIM_88E1111_PHY_LED_DIRECT, NULL},
+			   /* Read the Status */
+			   {MIIM_88E1011_PHY_STATUS, miim_read,
+			    &mii_parse_88E1011_psr},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+struct phy_info phy_info_cis8204 = {
+	0x3f11,
+	"Cicada Cis8204",
+	6,
+	(struct phy_cmd[]){	/* config */
+			   /* Override PHY config settings */
+			   {MIIM_CIS8201_AUX_CONSTAT,
+			    MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT,
+			    &mii_cis8204_fixled},
+			   {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT,
+			    &mii_cis8204_setmode},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_CIS8201_AUX_CONSTAT, miim_read,
+			    &mii_parse_cis8201},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+/* Cicada 8201 */
+struct phy_info phy_info_cis8201 = {
+	0xfc41,
+	"CIS8201",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Override PHY config settings */
+			   {MIIM_CIS8201_AUX_CONSTAT,
+			    MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
+			   /* Set up the interface mode */
+			   {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT,
+			    NULL},
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_CIS8201_AUX_CONSTAT, miim_read,
+			    &mii_parse_cis8201},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+struct phy_info phy_info_VSC8244 = {
+	0x3f1b,
+	"Vitesse VSC8244",
+	6,
+	(struct phy_cmd[]){	/* config */
+			   /* Override PHY config settings */
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_VSC8244_AUX_CONSTAT, miim_read,
+			    &mii_parse_vsc8244},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+struct phy_info phy_info_dm9161 = {
+	0x0181b88,
+	"Davicom DM9161E",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
+			   /* Do not bypass the scrambler/descrambler */
+			   {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
+			   /* Clear 10BTCSR to default */
+			   {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT,
+			    NULL},
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CR_INIT, NULL},
+			   /* Restart Auto Negotiation */
+			   {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Status is read once to clear old link state */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_DM9161_SCSR, miim_read,
+			    &mii_parse_dm9161_scsr},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+/* a generic flavor.  */
+struct phy_info phy_info_generic =  {
+	0,
+	"Unknown/Generic PHY",
+	32,
+	(struct phy_cmd[]) { /* config */
+		{PHY_BMCR, PHY_BMCR_RESET, NULL},
+		{PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* startup */
+		{PHY_BMSR, miim_read, NULL},
+		{PHY_BMSR, miim_read, &mii_parse_sr},
+		{PHY_BMSR, miim_read, &mii_parse_link},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* shutdown */
+		{miim_end,}
+	}
+};
+
+
+uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
+{
+	unsigned int speed;
+	if (priv->link) {
+		speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
+
+		switch (speed) {
+		case MIIM_LXT971_SR2_10HDX:
+			priv->speed = 10;
+			priv->duplexity = 0;
+			break;
+		case MIIM_LXT971_SR2_10FDX:
+			priv->speed = 10;
+			priv->duplexity = 1;
+			break;
+		case MIIM_LXT971_SR2_100HDX:
+			priv->speed = 100;
+			priv->duplexity = 0;
+			break;
+		default:
+			priv->speed = 100;
+			priv->duplexity = 1;
+		}
+	} else {
+		priv->speed = 0;
+		priv->duplexity = 0;
+	}
+
+	return 0;
+}
+
+static struct phy_info phy_info_lxt971 = {
+	0x0001378e,
+	"LXT971",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   {MIIM_CR, MIIM_CR_INIT, mii_cr_init},	/* autonegotiate */
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup - enable interrupts */
+			   /* { 0x12, 0x00f2, NULL }, */
+			   {MIIM_STATUS, miim_read, NULL},
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown - disable interrupts */
+			   {miim_end,}
+			   },
+};
+
+/* Parse the DP83865's link and auto-neg status register for speed and duplex
+ * information
+ */
+uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
+{
+	switch (mii_reg & MIIM_DP83865_SPD_MASK) {
+
+	case MIIM_DP83865_SPD_1000:
+		priv->speed = 1000;
+		break;
+
+	case MIIM_DP83865_SPD_100:
+		priv->speed = 100;
+		break;
+
+	default:
+		priv->speed = 10;
+		break;
+
+	}
+
+	if (mii_reg & MIIM_DP83865_DPX_FULL)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	return 0;
+}
+
+struct phy_info phy_info_dp83865 = {
+	0x20005c7,
+	"NatSemi DP83865",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Status is read once to clear old link state */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the link and auto-neg status */
+			   {MIIM_DP83865_LANR, miim_read,
+			    &mii_parse_dp83865_lanr},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+struct phy_info *phy_info[] = {
+	&phy_info_cis8204,
+	&phy_info_cis8201,
+	&phy_info_BCM5461S,
+	&phy_info_BCM5464S,
+	&phy_info_M88E1011S,
+	&phy_info_M88E1111S,
+	&phy_info_M88E1145,
+	&phy_info_M88E1149S,
+	&phy_info_dm9161,
+	&phy_info_lxt971,
+	&phy_info_VSC8244,
+	&phy_info_dp83865,
+	&phy_info_generic,
+	NULL
+};
+
+/* Grab the identifier of the device's PHY, and search through
+ * all of the known PHYs to see if one matches.	 If so, return
+ * it, if not, return NULL
+ */
+struct phy_info *get_phy_info(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	uint phy_reg, phy_ID;
+	int i;
+	struct phy_info *theInfo = NULL;
+
+	/* Grab the bits from PHYIR1, and put them in the upper half */
+	phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
+	phy_ID = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
+	phy_ID |= (phy_reg & 0xffff);
+
+	/* loop through all the known PHY types, and find one that */
+	/* matches the ID we read from the PHY. */
+	for (i = 0; phy_info[i]; i++) {
+		if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
+			theInfo = phy_info[i];
+			break;
+		}
+	}
+
+	if (theInfo == NULL) {
+		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
+		return NULL;
+	} else {
+		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
+	}
+
+	return theInfo;
+}
+
+/* Execute the given series of commands on the given device's
+ * PHY, running functions as necessary
+ */
+void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
+{
+	int i;
+	uint result;
+	volatile tsec_t *phyregs = priv->phyregs;
+
+	phyregs->miimcfg = MIIMCFG_RESET;
+
+	phyregs->miimcfg = MIIMCFG_INIT_VALUE;
+
+	while (phyregs->miimind & MIIMIND_BUSY) ;
+
+	for (i = 0; cmd->mii_reg != miim_end; i++) {
+		if (cmd->mii_data == miim_read) {
+			result = read_phy_reg(priv, cmd->mii_reg);
+
+			if (cmd->funct != NULL)
+				(*(cmd->funct)) (result, priv);
+
+		} else {
+			if (cmd->funct != NULL)
+				result = (*(cmd->funct)) (cmd->mii_reg, priv);
+			else
+				result = cmd->mii_data;
+
+			write_phy_reg(priv, cmd->mii_reg, result);
+
+		}
+		cmd++;
+	}
+}
+
+/* Relocate the function pointers in the phy cmd lists */
+static void relocate_cmds(void)
+{
+	struct phy_cmd **cmdlistptr;
+	struct phy_cmd *cmd;
+	int i, j, k;
+
+	for (i = 0; phy_info[i]; i++) {
+		/* First thing's first: relocate the pointers to the
+		 * PHY command structures (the structs were done) */
+		phy_info[i] = (struct phy_info *)((uint) phy_info[i]
+						  + gd->reloc_off);
+		phy_info[i]->name += gd->reloc_off;
+		phy_info[i]->config =
+		    (struct phy_cmd *)((uint) phy_info[i]->config
+				       + gd->reloc_off);
+		phy_info[i]->startup =
+		    (struct phy_cmd *)((uint) phy_info[i]->startup
+				       + gd->reloc_off);
+		phy_info[i]->shutdown =
+		    (struct phy_cmd *)((uint) phy_info[i]->shutdown
+				       + gd->reloc_off);
+
+		cmdlistptr = &phy_info[i]->config;
+		j = 0;
+		for (; cmdlistptr <= &phy_info[i]->shutdown; cmdlistptr++) {
+			k = 0;
+			for (cmd = *cmdlistptr;
+			     cmd->mii_reg != miim_end;
+			     cmd++) {
+				/* Only relocate non-NULL pointers */
+				if (cmd->funct)
+					cmd->funct += gd->reloc_off;
+
+				k++;
+			}
+			j++;
+		}
+	}
+
+	relocated = 1;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+
+struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
+{
+	int i;
+
+	for (i = 0; i < MAXCONTROLLERS; i++) {
+		if (privlist[i]->phyaddr == phyaddr)
+			return privlist[i];
+	}
+
+	return NULL;
+}
+
+/*
+ * Read a MII PHY register.
+ *
+ * Returns:
+ *  0 on success
+ */
+static int tsec_miiphy_read(char *devname, unsigned char addr,
+			    unsigned char reg, unsigned short *value)
+{
+	unsigned short ret;
+	struct tsec_private *priv = get_priv_for_phy(addr);
+
+	if (NULL == priv) {
+		printf("Can't read PHY at address %d\n", addr);
+		return -1;
+	}
+
+	ret = (unsigned short)read_phy_reg(priv, reg);
+	*value = ret;
+
+	return 0;
+}
+
+/*
+ * Write a MII PHY register.
+ *
+ * Returns:
+ *  0 on success
+ */
+static int tsec_miiphy_write(char *devname, unsigned char addr,
+			     unsigned char reg, unsigned short value)
+{
+	struct tsec_private *priv = get_priv_for_phy(addr);
+
+	if (NULL == priv) {
+		printf("Can't write PHY at address %d\n", addr);
+		return -1;
+	}
+
+	write_phy_reg(priv, reg, value);
+
+	return 0;
+}
+
+#endif
+
+#ifdef CONFIG_MCAST_TFTP
+
+/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
+
+/* Set the appropriate hash bit for the given addr */
+
+/* The algorithm works like so:
+ * 1) Take the Destination Address (ie the multicast address), and
+ * do a CRC on it (little endian), and reverse the bits of the
+ * result.
+ * 2) Use the 8 most significant bits as a hash into a 256-entry
+ * table.  The table is controlled through 8 32-bit registers:
+ * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is
+ * gaddr7.  This means that the 3 most significant bits in the
+ * hash index which gaddr register to use, and the 5 other bits
+ * indicate which bit (assuming an IBM numbering scheme, which
+ * for PowerPC (tm) is usually the case) in the tregister holds
+ * the entry. */
+static int
+tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
+{
+ struct tsec_private *priv = privlist[1];
+ volatile tsec_t *regs = priv->regs;
+ volatile u32  *reg_array, value;
+ u8 result, whichbit, whichreg;
+
+	result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff);
+	whichbit = result & 0x1f;	/* the 5 LSB = which bit to set */
+	whichreg = result >> 5;		/* the 3 MSB = which reg to set it in */
+	value = (1 << (31-whichbit));
+
+	reg_array = &(regs->hash.gaddr0);
+
+	if (set) {
+		reg_array[whichreg] |= value;
+	} else {
+		reg_array[whichreg] &= ~value;
+	}
+	return 0;
+}
+#endif /* Multicast TFTP ? */
+
+#endif /* CONFIG_TSEC_ENET */
diff --git a/drivers/net/tsec.h b/drivers/net/tsec.h
new file mode 100644
index 0000000..2f0092a
--- /dev/null
+++ b/drivers/net/tsec.h
@@ -0,0 +1,563 @@
+/*
+ *  tsec.h
+ *
+ *  Driver for the Motorola Triple Speed Ethernet Controller
+ *
+ *  This software may be used and distributed according to the
+ *  terms of the GNU Public License, Version 2, incorporated
+ *  herein by reference.
+ *
+ * Copyright 2004, 2007 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * maintained by Xianghua Xiao (x.xiao@motorola.com)
+ * author Andy Fleming
+ *
+ */
+
+#ifndef __TSEC_H
+#define __TSEC_H
+
+#include <net.h>
+#include <config.h>
+
+#ifndef CFG_TSEC1_OFFSET
+    #define CFG_TSEC1_OFFSET	(0x24000)
+#endif
+
+#define TSEC_SIZE	0x01000
+
+/* FIXME:  Should these be pushed back to 83xx and 85xx config files? */
+#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
+    #define TSEC_BASE_ADDR	(CFG_IMMR + CFG_TSEC1_OFFSET)
+#elif defined(CONFIG_MPC83XX)
+    #define TSEC_BASE_ADDR	(CFG_IMMR + CFG_TSEC1_OFFSET)
+#endif
+
+
+#define MAC_ADDR_LEN 6
+
+/* #define TSEC_TIMEOUT 	1000000 */
+#define TSEC_TIMEOUT 1000
+#define TOUT_LOOP 	1000000
+
+#define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
+
+/* MAC register bits */
+#define MACCFG1_SOFT_RESET	0x80000000
+#define MACCFG1_RESET_RX_MC	0x00080000
+#define MACCFG1_RESET_TX_MC	0x00040000
+#define MACCFG1_RESET_RX_FUN	0x00020000
+#define	MACCFG1_RESET_TX_FUN	0x00010000
+#define MACCFG1_LOOPBACK	0x00000100
+#define MACCFG1_RX_FLOW		0x00000020
+#define MACCFG1_TX_FLOW		0x00000010
+#define MACCFG1_SYNCD_RX_EN	0x00000008
+#define MACCFG1_RX_EN		0x00000004
+#define MACCFG1_SYNCD_TX_EN	0x00000002
+#define MACCFG1_TX_EN		0x00000001
+
+#define MACCFG2_INIT_SETTINGS	0x00007205
+#define MACCFG2_FULL_DUPLEX	0x00000001
+#define MACCFG2_IF              0x00000300
+#define MACCFG2_GMII		0x00000200
+#define MACCFG2_MII             0x00000100
+
+#define ECNTRL_INIT_SETTINGS	0x00001000
+#define ECNTRL_TBI_MODE         0x00000020
+#define ECNTRL_R100		0x00000008
+#define ECNTRL_SGMII_MODE	0x00000002
+
+#define miim_end -2
+#define miim_read -1
+
+#ifndef CFG_TBIPA_VALUE
+    #define CFG_TBIPA_VALUE	0x1f
+#endif
+#define MIIMCFG_INIT_VALUE	0x00000003
+#define MIIMCFG_RESET		0x80000000
+
+#define MIIMIND_BUSY            0x00000001
+#define MIIMIND_NOTVALID        0x00000004
+
+#define MIIM_CONTROL            0x00
+#define MIIM_CONTROL_RESET	0x00009140
+#define MIIM_CONTROL_INIT       0x00001140
+#define MIIM_CONTROL_RESTART    0x00001340
+#define MIIM_ANEN               0x00001000
+
+#define MIIM_CR                 0x00
+#define MIIM_CR_RST		0x00008000
+#define MIIM_CR_INIT	        0x00001000
+
+#define MIIM_STATUS		0x1
+#define MIIM_STATUS_AN_DONE 	0x00000020
+#define MIIM_STATUS_LINK	0x0004
+#define PHY_BMSR_AUTN_ABLE	0x0008
+#define PHY_BMSR_AUTN_COMP	0x0020
+
+#define MIIM_PHYIR1		0x2
+#define MIIM_PHYIR2		0x3
+
+#define MIIM_ANAR		0x4
+#define MIIM_ANAR_INIT		0x1e1
+
+#define MIIM_TBI_ANLPBPA	0x5
+#define MIIM_TBI_ANLPBPA_HALF	0x00000040
+#define MIIM_TBI_ANLPBPA_FULL	0x00000020
+
+#define MIIM_TBI_ANEX		0x6
+#define MIIM_TBI_ANEX_NP	0x00000004
+#define MIIM_TBI_ANEX_PRX	0x00000002
+
+#define MIIM_GBIT_CONTROL	0x9
+#define MIIM_GBIT_CONTROL_INIT	0xe00
+
+/* Broadcom BCM54xx -- taken from linux sungem_phy */
+#define MIIM_BCM54xx_AUXSTATUS			0x19
+#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK	0x0700
+#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT	8
+
+/* Cicada Auxiliary Control/Status Register */
+#define MIIM_CIS8201_AUX_CONSTAT        0x1c
+#define MIIM_CIS8201_AUXCONSTAT_INIT    0x0004
+#define MIIM_CIS8201_AUXCONSTAT_DUPLEX  0x0020
+#define MIIM_CIS8201_AUXCONSTAT_SPEED   0x0018
+#define MIIM_CIS8201_AUXCONSTAT_GBIT    0x0010
+#define MIIM_CIS8201_AUXCONSTAT_100     0x0008
+
+/* Cicada Extended Control Register 1 */
+#define MIIM_CIS8201_EXT_CON1           0x17
+#define MIIM_CIS8201_EXTCON1_INIT       0x0000
+
+/* Cicada 8204 Extended PHY Control Register 1 */
+#define MIIM_CIS8204_EPHY_CON		0x17
+#define MIIM_CIS8204_EPHYCON_INIT	0x0006
+#define MIIM_CIS8204_EPHYCON_RGMII	0x1100
+
+/* Cicada 8204 Serial LED Control Register */
+#define MIIM_CIS8204_SLED_CON		0x1b
+#define MIIM_CIS8204_SLEDCON_INIT	0x1115
+
+#define MIIM_GBIT_CON		0x09
+#define MIIM_GBIT_CON_ADVERT	0x0e00
+
+/* Entry for Vitesse VSC8244 regs starts here */
+/* Vitesse VSC8244 Auxiliary Control/Status Register */
+#define MIIM_VSC8244_AUX_CONSTAT        0x1c
+#define MIIM_VSC8244_AUXCONSTAT_INIT    0x0000
+#define MIIM_VSC8244_AUXCONSTAT_DUPLEX  0x0020
+#define MIIM_VSC8244_AUXCONSTAT_SPEED   0x0018
+#define MIIM_VSC8244_AUXCONSTAT_GBIT    0x0010
+#define MIIM_VSC8244_AUXCONSTAT_100     0x0008
+#define MIIM_CONTROL_INIT_LOOPBACK      0x4000
+
+/* Vitesse VSC8244 Extended PHY Control Register 1 */
+#define MIIM_VSC8244_EPHY_CON           0x17
+#define MIIM_VSC8244_EPHYCON_INIT       0x0006
+
+/* Vitesse VSC8244 Serial LED Control Register */
+#define MIIM_VSC8244_LED_CON            0x1b
+#define MIIM_VSC8244_LEDCON_INIT        0xF011
+
+/* 88E1011 PHY Status Register */
+#define MIIM_88E1011_PHY_STATUS         0x11
+#define MIIM_88E1011_PHYSTAT_SPEED      0xc000
+#define MIIM_88E1011_PHYSTAT_GBIT       0x8000
+#define MIIM_88E1011_PHYSTAT_100        0x4000
+#define MIIM_88E1011_PHYSTAT_DUPLEX     0x2000
+#define MIIM_88E1011_PHYSTAT_SPDDONE	0x0800
+#define MIIM_88E1011_PHYSTAT_LINK	0x0400
+
+#define MIIM_88E1011_PHY_SCR		0x10
+#define MIIM_88E1011_PHY_MDI_X_AUTO	0x0060
+
+/* 88E1111 PHY LED Control Register */
+#define MIIM_88E1111_PHY_LED_CONTROL   24
+#define MIIM_88E1111_PHY_LED_DIRECT    0x4100
+#define MIIM_88E1111_PHY_LED_COMBINE   0x411C
+
+/* 88E1145 Extended PHY Specific Control Register */
+#define MIIM_88E1145_PHY_EXT_CR 20
+#define MIIM_M88E1145_RGMII_RX_DELAY	0x0080
+#define MIIM_M88E1145_RGMII_TX_DELAY	0x0002
+
+#define MIIM_88E1145_PHY_PAGE   29
+#define MIIM_88E1145_PHY_CAL_OV 30
+
+
+/* DM9161 Control register values */
+#define MIIM_DM9161_CR_STOP	0x0400
+#define MIIM_DM9161_CR_RSTAN	0x1200
+
+#define MIIM_DM9161_SCR		0x10
+#define MIIM_DM9161_SCR_INIT	0x0610
+
+/* DM9161 Specified Configuration and Status Register */
+#define MIIM_DM9161_SCSR	0x11
+#define MIIM_DM9161_SCSR_100F	0x8000
+#define MIIM_DM9161_SCSR_100H	0x4000
+#define MIIM_DM9161_SCSR_10F	0x2000
+#define MIIM_DM9161_SCSR_10H	0x1000
+
+/* DM9161 10BT Configuration/Status */
+#define MIIM_DM9161_10BTCSR	0x12
+#define MIIM_DM9161_10BTCSR_INIT	0x7800
+
+/* LXT971 Status 2 registers */
+#define MIIM_LXT971_SR2              0x11  /* Status Register 2  */
+#define MIIM_LXT971_SR2_SPEED_MASK 0x4200
+#define MIIM_LXT971_SR2_10HDX      0x0000  /*  10 Mbit half duplex selected */
+#define MIIM_LXT971_SR2_10FDX      0x0200  /*  10 Mbit full duplex selected */
+#define MIIM_LXT971_SR2_100HDX     0x4000  /* 100 Mbit half duplex selected */
+#define MIIM_LXT971_SR2_100FDX     0x4200  /* 100 Mbit full duplex selected */
+
+/* DP83865 Control register values */
+#define MIIM_DP83865_CR_INIT	0x9200
+
+/* DP83865 Link and Auto-Neg Status Register */
+#define MIIM_DP83865_LANR	0x11
+#define MIIM_DP83865_SPD_MASK	0x0018
+#define MIIM_DP83865_SPD_1000	0x0010
+#define MIIM_DP83865_SPD_100	0x0008
+#define MIIM_DP83865_DPX_FULL	0x0002
+
+#define MIIM_READ_COMMAND       0x00000001
+
+#define MRBLR_INIT_SETTINGS	PKTSIZE_ALIGN
+
+#define MINFLR_INIT_SETTINGS	0x00000040
+
+#define DMACTRL_INIT_SETTINGS   0x000000c3
+#define DMACTRL_GRS             0x00000010
+#define DMACTRL_GTS             0x00000008
+
+#define TSTAT_CLEAR_THALT       0x80000000
+#define RSTAT_CLEAR_RHALT       0x00800000
+
+
+#define IEVENT_INIT_CLEAR	0xffffffff
+#define IEVENT_BABR		0x80000000
+#define IEVENT_RXC		0x40000000
+#define IEVENT_BSY		0x20000000
+#define IEVENT_EBERR		0x10000000
+#define IEVENT_MSRO		0x04000000
+#define IEVENT_GTSC		0x02000000
+#define IEVENT_BABT		0x01000000
+#define IEVENT_TXC		0x00800000
+#define IEVENT_TXE		0x00400000
+#define IEVENT_TXB		0x00200000
+#define IEVENT_TXF		0x00100000
+#define IEVENT_IE		0x00080000
+#define IEVENT_LC		0x00040000
+#define IEVENT_CRL		0x00020000
+#define IEVENT_XFUN		0x00010000
+#define IEVENT_RXB0		0x00008000
+#define IEVENT_GRSC		0x00000100
+#define IEVENT_RXF0		0x00000080
+
+#define IMASK_INIT_CLEAR	0x00000000
+#define IMASK_TXEEN		0x00400000
+#define IMASK_TXBEN		0x00200000
+#define IMASK_TXFEN             0x00100000
+#define IMASK_RXFEN0		0x00000080
+
+
+/* Default Attribute fields */
+#define ATTR_INIT_SETTINGS     0x000000c0
+#define ATTRELI_INIT_SETTINGS  0x00000000
+
+
+/* TxBD status field bits */
+#define TXBD_READY		0x8000
+#define TXBD_PADCRC		0x4000
+#define TXBD_WRAP		0x2000
+#define TXBD_INTERRUPT		0x1000
+#define TXBD_LAST		0x0800
+#define TXBD_CRC		0x0400
+#define TXBD_DEF		0x0200
+#define TXBD_HUGEFRAME		0x0080
+#define TXBD_LATECOLLISION	0x0080
+#define TXBD_RETRYLIMIT		0x0040
+#define	TXBD_RETRYCOUNTMASK	0x003c
+#define TXBD_UNDERRUN		0x0002
+#define TXBD_STATS              0x03ff
+
+/* RxBD status field bits */
+#define RXBD_EMPTY		0x8000
+#define RXBD_RO1		0x4000
+#define RXBD_WRAP		0x2000
+#define RXBD_INTERRUPT		0x1000
+#define RXBD_LAST		0x0800
+#define RXBD_FIRST		0x0400
+#define RXBD_MISS		0x0100
+#define RXBD_BROADCAST		0x0080
+#define RXBD_MULTICAST		0x0040
+#define RXBD_LARGE		0x0020
+#define RXBD_NONOCTET		0x0010
+#define RXBD_SHORT		0x0008
+#define RXBD_CRCERR		0x0004
+#define RXBD_OVERRUN		0x0002
+#define RXBD_TRUNCATED		0x0001
+#define RXBD_STATS		0x003f
+
+typedef struct txbd8
+{
+	ushort       status;         /* Status Fields */
+	ushort       length;         /* Buffer length */
+	uint         bufPtr;         /* Buffer Pointer */
+} txbd8_t;
+
+typedef struct rxbd8
+{
+	ushort       status;         /* Status Fields */
+	ushort       length;         /* Buffer Length */
+	uint         bufPtr;         /* Buffer Pointer */
+} rxbd8_t;
+
+typedef struct rmon_mib
+{
+	/* Transmit and Receive Counters */
+	uint	tr64;		/* Transmit and Receive 64-byte Frame Counter */
+	uint	tr127;		/* Transmit and Receive 65-127 byte Frame Counter */
+	uint	tr255;		/* Transmit and Receive 128-255 byte Frame Counter */
+	uint	tr511;		/* Transmit and Receive 256-511 byte Frame Counter */
+	uint	tr1k;		/* Transmit and Receive 512-1023 byte Frame Counter */
+	uint	trmax;		/* Transmit and Receive 1024-1518 byte Frame Counter */
+	uint	trmgv;		/* Transmit and Receive 1519-1522 byte Good VLAN Frame */
+	/* Receive Counters */
+	uint	rbyt;		/* Receive Byte Counter */
+	uint	rpkt;		/* Receive Packet Counter */
+	uint	rfcs;		/* Receive FCS Error Counter */
+	uint	rmca;		/* Receive Multicast Packet (Counter) */
+	uint	rbca;		/* Receive Broadcast Packet */
+	uint	rxcf;		/* Receive Control Frame Packet */
+	uint	rxpf;		/* Receive Pause Frame Packet */
+	uint	rxuo;		/* Receive Unknown OP Code */
+	uint	raln;		/* Receive Alignment Error */
+	uint	rflr;		/* Receive Frame Length Error */
+	uint	rcde;		/* Receive Code Error */
+	uint	rcse;		/* Receive Carrier Sense Error */
+	uint	rund;		/* Receive Undersize Packet */
+	uint	rovr;		/* Receive Oversize Packet */
+	uint	rfrg;		/* Receive Fragments */
+	uint	rjbr;		/* Receive Jabber */
+	uint	rdrp;		/* Receive Drop */
+	/* Transmit Counters */
+	uint	tbyt;		/* Transmit Byte Counter */
+	uint	tpkt;		/* Transmit Packet */
+	uint	tmca;		/* Transmit Multicast Packet */
+	uint	tbca;		/* Transmit Broadcast Packet */
+	uint	txpf;		/* Transmit Pause Control Frame */
+	uint	tdfr;		/* Transmit Deferral Packet */
+	uint	tedf;		/* Transmit Excessive Deferral Packet */
+	uint	tscl;		/* Transmit Single Collision Packet */
+	/* (0x2_n700) */
+	uint	tmcl;		/* Transmit Multiple Collision Packet */
+	uint	tlcl;		/* Transmit Late Collision Packet */
+	uint	txcl;		/* Transmit Excessive Collision Packet */
+	uint	tncl;		/* Transmit Total Collision */
+
+	uint	res2;
+
+	uint	tdrp;		/* Transmit Drop Frame */
+	uint	tjbr;		/* Transmit Jabber Frame */
+	uint	tfcs;		/* Transmit FCS Error */
+	uint	txcf;		/* Transmit Control Frame */
+	uint	tovr;		/* Transmit Oversize Frame */
+	uint	tund;		/* Transmit Undersize Frame */
+	uint	tfrg;		/* Transmit Fragments Frame */
+	/* General Registers */
+	uint	car1;		/* Carry Register One */
+	uint	car2;		/* Carry Register Two */
+	uint	cam1;		/* Carry Register One Mask */
+	uint	cam2;		/* Carry Register Two Mask */
+} rmon_mib_t;
+
+typedef struct tsec_hash_regs
+{
+	uint	iaddr0;		/* Individual Address Register 0 */
+	uint	iaddr1;		/* Individual Address Register 1 */
+	uint	iaddr2;		/* Individual Address Register 2 */
+	uint	iaddr3;		/* Individual Address Register 3 */
+	uint	iaddr4;		/* Individual Address Register 4 */
+	uint	iaddr5;		/* Individual Address Register 5 */
+	uint	iaddr6;		/* Individual Address Register 6 */
+	uint	iaddr7;		/* Individual Address Register 7 */
+	uint	res1[24];
+	uint	gaddr0;		/* Group Address Register 0 */
+	uint	gaddr1;		/* Group Address Register 1 */
+	uint	gaddr2;		/* Group Address Register 2 */
+	uint	gaddr3;		/* Group Address Register 3 */
+	uint	gaddr4;		/* Group Address Register 4 */
+	uint	gaddr5;		/* Group Address Register 5 */
+	uint	gaddr6;		/* Group Address Register 6 */
+	uint	gaddr7;		/* Group Address Register 7 */
+	uint	res2[24];
+} tsec_hash_t;
+
+typedef struct tsec
+{
+	/* General Control and Status Registers (0x2_n000) */
+	uint	res000[4];
+
+	uint	ievent;		/* Interrupt Event */
+	uint	imask;		/* Interrupt Mask */
+	uint	edis;		/* Error Disabled */
+	uint	res01c;
+	uint	ecntrl;		/* Ethernet Control */
+	uint	minflr;		/* Minimum Frame Length */
+	uint	ptv;		/* Pause Time Value */
+	uint	dmactrl;	/* DMA Control */
+	uint	tbipa;		/* TBI PHY Address */
+
+	uint	res034[3];
+	uint	res040[48];
+
+	/* Transmit Control and Status Registers (0x2_n100) */
+	uint	tctrl;		/* Transmit Control */
+	uint 	tstat;		/* Transmit Status */
+	uint	res108;
+	uint	tbdlen;		/* Tx BD Data Length */
+	uint	res110[5];
+	uint	ctbptr;	        /* Current TxBD Pointer */
+	uint	res128[23];
+	uint	tbptr;		/* TxBD Pointer */
+	uint	res188[30];
+	/* (0x2_n200) */
+	uint        res200;
+	uint	tbase;		/* TxBD Base Address */
+	uint	res208[42];
+	uint	ostbd;		/* Out of Sequence TxBD */
+	uint	ostbdp;		/* Out of Sequence Tx Data Buffer Pointer */
+	uint        res2b8[18];
+
+	/* Receive Control and Status Registers (0x2_n300) */
+	uint	rctrl;		/* Receive Control */
+	uint	rstat;		/* Receive Status */
+	uint	res308;
+	uint	rbdlen;		/* RxBD Data Length */
+	uint	res310[4];
+	uint        res320;
+	uint	crbptr; 	/* Current Receive Buffer Pointer */
+	uint	res328[6];
+	uint	mrblr;  	/* Maximum Receive Buffer Length */
+	uint	res344[16];
+	uint	rbptr;   	/* RxBD Pointer */
+	uint        res388[30];
+	/* (0x2_n400) */
+	uint        res400;
+	uint	rbase;  	/* RxBD Base Address */
+	uint        res408[62];
+
+	/* MAC Registers (0x2_n500) */
+	uint	maccfg1;	/* MAC Configuration #1 */
+	uint	maccfg2;	/* MAC Configuration #2 */
+	uint	ipgifg;		/* Inter Packet Gap/Inter Frame Gap */
+	uint	hafdup;		/* Half-duplex */
+	uint	maxfrm;		/* Maximum Frame */
+	uint	res514;
+	uint	res518;
+
+	uint	res51c;
+
+	uint	miimcfg;	/* MII Management: Configuration */
+	uint	miimcom;	/* MII Management: Command */
+	uint	miimadd;	/* MII Management: Address */
+	uint	miimcon;	/* MII Management: Control */
+	uint	miimstat;	/* MII Management: Status */
+	uint	miimind;	/* MII Management: Indicators */
+
+	uint	res538;
+
+	uint	ifstat;		/* Interface Status */
+	uint	macstnaddr1;	/* Station Address, part 1 */
+	uint	macstnaddr2;	/* Station Address, part 2 */
+	uint	res548[46];
+
+	/* (0x2_n600) */
+	uint	res600[32];
+
+	/* RMON MIB Registers (0x2_n680-0x2_n73c) */
+	rmon_mib_t	rmon;
+	uint	res740[48];
+
+	/* Hash Function Registers (0x2_n800) */
+	tsec_hash_t	hash;
+
+	uint        res900[128];
+
+	/* Pattern Registers (0x2_nb00) */
+	uint        resb00[62];
+	uint        attr;          /* Default Attribute Register */
+	uint        attreli;       /* Default Attribute Extract Length and Index */
+
+	/* TSEC Future Expansion Space (0x2_nc00-0x2_nffc) */
+	uint	resc00[256];
+} tsec_t;
+
+#define TSEC_GIGABIT (1)
+
+/* This flag currently only has
+ * meaning if we're using the eTSEC */
+#define TSEC_REDUCED (1 << 1)
+
+struct tsec_private {
+	volatile tsec_t *regs;
+	volatile tsec_t *phyregs;
+	struct phy_info *phyinfo;
+	uint phyaddr;
+	u32 flags;
+	uint link;
+	uint duplexity;
+	uint speed;
+};
+
+
+/*
+ * struct phy_cmd:  A command for reading or writing a PHY register
+ *
+ * mii_reg:  The register to read or write
+ *
+ * mii_data:  For writes, the value to put in the register.
+ * 	A value of -1 indicates this is a read.
+ *
+ * funct: A function pointer which is invoked for each command.
+ * 	For reads, this function will be passed the value read
+ *	from the PHY, and process it.
+ *	For writes, the result of this function will be written
+ *	to the PHY register
+ */
+struct phy_cmd {
+    uint mii_reg;
+    uint mii_data;
+    uint (*funct) (uint mii_reg, struct tsec_private* priv);
+};
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ *
+ * id will contain a number which represents the PHY.  During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is.  The 32-bit result
+ * gotten from the PHY will be shifted right by "shift" bits to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ * The struct phy_cmd entries represent pointers to an arrays of
+ * commands which tell the driver what to do to the PHY.
+ */
+struct phy_info {
+    uint id;
+    char *name;
+    uint shift;
+    /* Called to configure the PHY, and modify the controller
+     * based on the results */
+    struct phy_cmd *config;
+
+    /* Called when starting up the controller */
+    struct phy_cmd *startup;
+
+    /* Called when bringing down the controller */
+    struct phy_cmd *shutdown;
+};
+
+#endif /* __TSEC_H */
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
new file mode 100644
index 0000000..524e9da
--- /dev/null
+++ b/drivers/net/tsi108_eth.c
@@ -0,0 +1,1036 @@
+/***********************************************************************
+ *
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Description:
+ *   Ethernet interface for Tundra TSI108 bridge chip
+ *
+ ***********************************************************************/
+
+#include <config.h>
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) \
+	&& defined(CONFIG_TSI108_ETH)
+
+#if !defined(CONFIG_TSI108_ETH_NUM_PORTS) || (CONFIG_TSI108_ETH_NUM_PORTS > 2)
+#error "CONFIG_TSI108_ETH_NUM_PORTS must be defined as 1 or 2"
+#endif
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/cache.h>
+
+#ifdef DEBUG
+#define TSI108_ETH_DEBUG 7
+#else
+#define TSI108_ETH_DEBUG 0
+#endif
+
+#if TSI108_ETH_DEBUG > 0
+#define debug_lev(lev, fmt, args...) \
+if (lev <= TSI108_ETH_DEBUG) \
+printf ("%s %d: " fmt, __FUNCTION__, __LINE__, ##args)
+#else
+#define debug_lev(lev, fmt, args...) do{}while(0)
+#endif
+
+#define RX_PRINT_ERRORS
+#define TX_PRINT_ERRORS
+
+#define ETH_BASE	(CFG_TSI108_CSR_BASE + 0x6000)
+
+#define ETH_PORT_OFFSET	0x400
+
+#define __REG32(base, offset) (*((volatile u32 *)((char *)(base) + (offset))))
+
+#define reg_MAC_CONFIG_1(base)		__REG32(base, 0x00000000)
+#define MAC_CONFIG_1_TX_ENABLE		(0x00000001)
+#define MAC_CONFIG_1_SYNC_TX_ENABLE	(0x00000002)
+#define MAC_CONFIG_1_RX_ENABLE		(0x00000004)
+#define MAC_CONFIG_1_SYNC_RX_ENABLE	(0x00000008)
+#define MAC_CONFIG_1_TX_FLOW_CONTROL	(0x00000010)
+#define MAC_CONFIG_1_RX_FLOW_CONTROL	(0x00000020)
+#define MAC_CONFIG_1_LOOP_BACK		(0x00000100)
+#define MAC_CONFIG_1_RESET_TX_FUNCTION	(0x00010000)
+#define MAC_CONFIG_1_RESET_RX_FUNCTION	(0x00020000)
+#define MAC_CONFIG_1_RESET_TX_MAC	(0x00040000)
+#define MAC_CONFIG_1_RESET_RX_MAC	(0x00080000)
+#define MAC_CONFIG_1_SIM_RESET		(0x40000000)
+#define MAC_CONFIG_1_SOFT_RESET		(0x80000000)
+
+#define reg_MAC_CONFIG_2(base)		__REG32(base, 0x00000004)
+#define MAC_CONFIG_2_FULL_DUPLEX	(0x00000001)
+#define MAC_CONFIG_2_CRC_ENABLE		(0x00000002)
+#define MAC_CONFIG_2_PAD_CRC		(0x00000004)
+#define MAC_CONFIG_2_LENGTH_CHECK	(0x00000010)
+#define MAC_CONFIG_2_HUGE_FRAME		(0x00000020)
+#define MAC_CONFIG_2_INTERFACE_MODE(val)	(((val) & 0x3) << 8)
+#define MAC_CONFIG_2_PREAMBLE_LENGTH(val)	(((val) & 0xf) << 12)
+#define INTERFACE_MODE_NIBBLE		1	/* 10/100 Mb/s MII) */
+#define INTERFACE_MODE_BYTE		2	/* 1000 Mb/s GMII/TBI */
+
+#define reg_MAXIMUM_FRAME_LENGTH(base)		__REG32(base, 0x00000010)
+
+#define reg_MII_MGMT_CONFIG(base)		__REG32(base, 0x00000020)
+#define MII_MGMT_CONFIG_MGMT_CLOCK_SELECT(val)	((val) & 0x7)
+#define MII_MGMT_CONFIG_NO_PREAMBLE		(0x00000010)
+#define MII_MGMT_CONFIG_SCAN_INCREMENT		(0x00000020)
+#define MII_MGMT_CONFIG_RESET_MGMT		(0x80000000)
+
+#define reg_MII_MGMT_COMMAND(base)		__REG32(base, 0x00000024)
+#define MII_MGMT_COMMAND_READ_CYCLE		(0x00000001)
+#define MII_MGMT_COMMAND_SCAN_CYCLE		(0x00000002)
+
+#define reg_MII_MGMT_ADDRESS(base)		__REG32(base, 0x00000028)
+#define reg_MII_MGMT_CONTROL(base)		__REG32(base, 0x0000002c)
+#define reg_MII_MGMT_STATUS(base)		__REG32(base, 0x00000030)
+
+#define reg_MII_MGMT_INDICATORS(base)		__REG32(base, 0x00000034)
+#define MII_MGMT_INDICATORS_BUSY		(0x00000001)
+#define MII_MGMT_INDICATORS_SCAN		(0x00000002)
+#define MII_MGMT_INDICATORS_NOT_VALID		(0x00000004)
+
+#define reg_INTERFACE_STATUS(base)		__REG32(base, 0x0000003c)
+#define INTERFACE_STATUS_LINK_FAIL		(0x00000008)
+#define INTERFACE_STATUS_EXCESS_DEFER		(0x00000200)
+
+#define reg_STATION_ADDRESS_1(base)		__REG32(base, 0x00000040)
+#define reg_STATION_ADDRESS_2(base)		__REG32(base, 0x00000044)
+
+#define reg_PORT_CONTROL(base)			__REG32(base, 0x00000200)
+#define PORT_CONTROL_PRI		(0x00000001)
+#define PORT_CONTROL_BPT		(0x00010000)
+#define PORT_CONTROL_SPD		(0x00040000)
+#define PORT_CONTROL_RBC		(0x00080000)
+#define PORT_CONTROL_PRB		(0x00200000)
+#define PORT_CONTROL_DIS		(0x00400000)
+#define PORT_CONTROL_TBI		(0x00800000)
+#define PORT_CONTROL_STE		(0x10000000)
+#define PORT_CONTROL_ZOR		(0x20000000)
+#define PORT_CONTROL_CLR		(0x40000000)
+#define PORT_CONTROL_SRT		(0x80000000)
+
+#define reg_TX_CONFIG(base)		__REG32(base, 0x00000220)
+#define TX_CONFIG_START_Q		(0x00000003)
+#define TX_CONFIG_EHP			(0x00400000)
+#define TX_CONFIG_CHP			(0x00800000)
+#define TX_CONFIG_RST			(0x80000000)
+
+#define reg_TX_CONTROL(base)		__REG32(base, 0x00000224)
+#define TX_CONTROL_GO			(0x00008000)
+#define TX_CONTROL_MP			(0x01000000)
+#define TX_CONTROL_EAI			(0x20000000)
+#define TX_CONTROL_ABT			(0x40000000)
+#define TX_CONTROL_EII			(0x80000000)
+
+#define reg_TX_STATUS(base)		__REG32(base, 0x00000228)
+#define TX_STATUS_QUEUE_USABLE		(0x0000000f)
+#define TX_STATUS_CURR_Q		(0x00000300)
+#define TX_STATUS_ACT			(0x00008000)
+#define TX_STATUS_QUEUE_IDLE		(0x000f0000)
+#define TX_STATUS_EOQ_PENDING		(0x0f000000)
+
+#define reg_TX_EXTENDED_STATUS(base)		__REG32(base, 0x0000022c)
+#define TX_EXTENDED_STATUS_END_OF_QUEUE_CONDITION		(0x0000000f)
+#define TX_EXTENDED_STATUS_END_OF_FRAME_CONDITION		(0x00000f00)
+#define TX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION	(0x000f0000)
+#define TX_EXTENDED_STATUS_ERROR_FLAG				(0x0f000000)
+
+#define reg_TX_THRESHOLDS(base)			__REG32(base, 0x00000230)
+
+#define reg_TX_DIAGNOSTIC_ADDR(base)           __REG32(base, 0x00000270)
+#define TX_DIAGNOSTIC_ADDR_INDEX		(0x0000007f)
+#define TX_DIAGNOSTIC_ADDR_DFR			(0x40000000)
+#define TX_DIAGNOSTIC_ADDR_AI			(0x80000000)
+
+#define reg_TX_DIAGNOSTIC_DATA(base)		__REG32(base, 0x00000274)
+
+#define reg_TX_ERROR_STATUS(base)		__REG32(base, 0x00000278)
+#define TX_ERROR_STATUS				(0x00000278)
+#define TX_ERROR_STATUS_QUEUE_0_ERROR_RESPONSE	(0x0000000f)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_0		(0x00000010)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_0		(0x00000020)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_0		(0x00000040)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_0		(0x00000080)
+#define TX_ERROR_STATUS_QUEUE_1_ERROR_RESPONSE	(0x00000f00)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_1		(0x00001000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_1		(0x00002000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_1		(0x00004000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_1		(0x00008000)
+#define TX_ERROR_STATUS_QUEUE_2_ERROR_RESPONSE	(0x000f0000)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_2		(0x00100000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_2		(0x00200000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_2		(0x00400000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_2		(0x00800000)
+#define TX_ERROR_STATUS_QUEUE_3_ERROR_RESPONSE	(0x0f000000)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_3		(0x10000000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_3		(0x20000000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_3		(0x40000000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_3		(0x80000000)
+
+#define reg_TX_QUEUE_0_CONFIG(base)		__REG32(base, 0x00000280)
+#define TX_QUEUE_0_CONFIG_OCN_PORT		(0x0000003f)
+#define TX_QUEUE_0_CONFIG_BSWP			(0x00000400)
+#define TX_QUEUE_0_CONFIG_WSWP			(0x00000800)
+#define TX_QUEUE_0_CONFIG_AM			(0x00004000)
+#define TX_QUEUE_0_CONFIG_GVI			(0x00008000)
+#define TX_QUEUE_0_CONFIG_EEI			(0x00010000)
+#define TX_QUEUE_0_CONFIG_ELI			(0x00020000)
+#define TX_QUEUE_0_CONFIG_ENI			(0x00040000)
+#define TX_QUEUE_0_CONFIG_ESI			(0x00080000)
+#define TX_QUEUE_0_CONFIG_EDI			(0x00100000)
+
+#define reg_TX_QUEUE_0_BUF_CONFIG(base)		__REG32(base, 0x00000284)
+#define TX_QUEUE_0_BUF_CONFIG_OCN_PORT		(0x0000003f)
+#define TX_QUEUE_0_BUF_CONFIG_BURST		(0x00000300)
+#define TX_QUEUE_0_BUF_CONFIG_BSWP		(0x00000400)
+#define TX_QUEUE_0_BUF_CONFIG_WSWP		(0x00000800)
+
+#define OCN_PORT_HLP			0	/* HLP Interface */
+#define OCN_PORT_PCI_X			1	/* PCI-X Interface */
+#define OCN_PORT_PROCESSOR_MASTER	2	/* Processor Interface (master) */
+#define OCN_PORT_PROCESSOR_SLAVE	3	/* Processor Interface (slave) */
+#define OCN_PORT_MEMORY			4	/* Memory Controller */
+#define OCN_PORT_DMA			5	/* DMA Controller */
+#define OCN_PORT_ETHERNET		6	/* Ethernet Controller */
+#define OCN_PORT_PRINT			7	/* Print Engine Interface */
+
+#define reg_TX_QUEUE_0_PTR_LOW(base)		__REG32(base, 0x00000288)
+
+#define reg_TX_QUEUE_0_PTR_HIGH(base)		__REG32(base, 0x0000028c)
+#define TX_QUEUE_0_PTR_HIGH_VALID		(0x80000000)
+
+#define reg_RX_CONFIG(base)			__REG32(base, 0x00000320)
+#define RX_CONFIG_DEF_Q				(0x00000003)
+#define RX_CONFIG_EMF				(0x00000100)
+#define RX_CONFIG_EUF				(0x00000200)
+#define RX_CONFIG_BFE				(0x00000400)
+#define RX_CONFIG_MFE				(0x00000800)
+#define RX_CONFIG_UFE				(0x00001000)
+#define RX_CONFIG_SE				(0x00002000)
+#define RX_CONFIG_ABF				(0x00200000)
+#define RX_CONFIG_APE				(0x00400000)
+#define RX_CONFIG_CHP				(0x00800000)
+#define RX_CONFIG_RST				(0x80000000)
+
+#define reg_RX_CONTROL(base)			__REG32(base, 0x00000324)
+#define GE_E0_RX_CONTROL_QUEUE_ENABLES		(0x0000000f)
+#define GE_E0_RX_CONTROL_GO			(0x00008000)
+#define GE_E0_RX_CONTROL_EAI			(0x20000000)
+#define GE_E0_RX_CONTROL_ABT			(0x40000000)
+#define GE_E0_RX_CONTROL_EII			(0x80000000)
+
+#define reg_RX_EXTENDED_STATUS(base)		__REG32(base, 0x0000032c)
+#define RX_EXTENDED_STATUS			(0x0000032c)
+#define RX_EXTENDED_STATUS_EOQ			(0x0000000f)
+#define RX_EXTENDED_STATUS_EOQ_0		(0x00000001)
+#define RX_EXTENDED_STATUS_EOF			(0x00000f00)
+#define RX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION	(0x000f0000)
+#define RX_EXTENDED_STATUS_ERROR_FLAG				(0x0f000000)
+
+#define reg_RX_THRESHOLDS(base)			__REG32(base, 0x00000330)
+
+#define reg_RX_DIAGNOSTIC_ADDR(base)		__REG32(base, 0x00000370)
+#define RX_DIAGNOSTIC_ADDR_INDEX		(0x0000007f)
+#define RX_DIAGNOSTIC_ADDR_DFR			(0x40000000)
+#define RX_DIAGNOSTIC_ADDR_AI			(0x80000000)
+
+#define reg_RX_DIAGNOSTIC_DATA(base)		__REG32(base, 0x00000374)
+
+#define reg_RX_QUEUE_0_CONFIG(base)		__REG32(base, 0x00000380)
+#define RX_QUEUE_0_CONFIG_OCN_PORT		(0x0000003f)
+#define RX_QUEUE_0_CONFIG_BSWP			(0x00000400)
+#define RX_QUEUE_0_CONFIG_WSWP			(0x00000800)
+#define RX_QUEUE_0_CONFIG_AM			(0x00004000)
+#define RX_QUEUE_0_CONFIG_EEI			(0x00010000)
+#define RX_QUEUE_0_CONFIG_ELI			(0x00020000)
+#define RX_QUEUE_0_CONFIG_ENI			(0x00040000)
+#define RX_QUEUE_0_CONFIG_ESI			(0x00080000)
+#define RX_QUEUE_0_CONFIG_EDI			(0x00100000)
+
+#define reg_RX_QUEUE_0_BUF_CONFIG(base)		__REG32(base, 0x00000384)
+#define RX_QUEUE_0_BUF_CONFIG_OCN_PORT		(0x0000003f)
+#define RX_QUEUE_0_BUF_CONFIG_BURST		(0x00000300)
+#define RX_QUEUE_0_BUF_CONFIG_BSWP		(0x00000400)
+#define RX_QUEUE_0_BUF_CONFIG_WSWP		(0x00000800)
+
+#define reg_RX_QUEUE_0_PTR_LOW(base)		__REG32(base, 0x00000388)
+
+#define reg_RX_QUEUE_0_PTR_HIGH(base)		__REG32(base, 0x0000038c)
+#define RX_QUEUE_0_PTR_HIGH_VALID		(0x80000000)
+
+/*
+ *  PHY register definitions
+ */
+/* the first 15 PHY registers are standard. */
+#define PHY_CTRL_REG		0	/* Control Register */
+#define PHY_STATUS_REG		1	/* Status Regiser */
+#define PHY_ID1_REG		2	/* Phy Id Reg (word 1) */
+#define PHY_ID2_REG		3	/* Phy Id Reg (word 2) */
+#define PHY_AN_ADV_REG		4	/* Autoneg Advertisement */
+#define PHY_LP_ABILITY_REG	5	/* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP_REG	6	/* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX_REG	7	/* Next Page TX */
+#define PHY_LP_NEXT_PAGE_REG	8	/* Link Partner Next Page */
+#define PHY_1000T_CTRL_REG	9	/* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS_REG	10	/* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS_REG	11	/* Extended Status Reg */
+
+/*
+ * PHY Register bit masks.
+ */
+#define PHY_CTRL_RESET		(1 << 15)
+#define PHY_CTRL_LOOPBACK	(1 << 14)
+#define PHY_CTRL_SPEED0		(1 << 13)
+#define PHY_CTRL_AN_EN		(1 << 12)
+#define PHY_CTRL_PWR_DN		(1 << 11)
+#define PHY_CTRL_ISOLATE	(1 << 10)
+#define PHY_CTRL_RESTART_AN	(1 << 9)
+#define PHY_CTRL_FULL_DUPLEX	(1 << 8)
+#define PHY_CTRL_CT_EN		(1 << 7)
+#define PHY_CTRL_SPEED1		(1 << 6)
+
+#define PHY_STAT_100BASE_T4	(1 << 15)
+#define PHY_STAT_100BASE_X_FD	(1 << 14)
+#define PHY_STAT_100BASE_X_HD	(1 << 13)
+#define PHY_STAT_10BASE_T_FD	(1 << 12)
+#define PHY_STAT_10BASE_T_HD	(1 << 11)
+#define PHY_STAT_100BASE_T2_FD	(1 << 10)
+#define PHY_STAT_100BASE_T2_HD	(1 << 9)
+#define PHY_STAT_EXT_STAT	(1 << 8)
+#define PHY_STAT_RESERVED	(1 << 7)
+#define PHY_STAT_MFPS		(1 << 6)	/* Management Frames Preamble Suppression */
+#define PHY_STAT_AN_COMPLETE	(1 << 5)
+#define PHY_STAT_REM_FAULT	(1 << 4)
+#define PHY_STAT_AN_CAP		(1 << 3)
+#define PHY_STAT_LINK_UP	(1 << 2)
+#define PHY_STAT_JABBER		(1 << 1)
+#define PHY_STAT_EXT_CAP	(1 << 0)
+
+#define TBI_CONTROL_2					0x11
+#define TBI_CONTROL_2_ENABLE_COMMA_DETECT		0x0001
+#define TBI_CONTROL_2_ENABLE_WRAP			0x0002
+#define TBI_CONTROL_2_G_MII_MODE			0x0010
+#define TBI_CONTROL_2_RECEIVE_CLOCK_SELECT		0x0020
+#define TBI_CONTROL_2_AUTO_NEGOTIATION_SENSE		0x0100
+#define TBI_CONTROL_2_DISABLE_TRANSMIT_RUNNING_DISPARITY	0x1000
+#define TBI_CONTROL_2_DISABLE_RECEIVE_RUNNING_DISPARITY		0x2000
+#define TBI_CONTROL_2_SHORTCUT_LINK_TIMER			0x4000
+#define TBI_CONTROL_2_SOFT_RESET				0x8000
+
+/* marvel specific */
+#define MV1111_EXT_CTRL1_REG	16	/* PHY Specific Control Reg */
+#define MV1111_SPEC_STAT_REG	17	/* PHY Specific Status Reg */
+#define MV1111_EXT_CTRL2_REG	20	/* Extended PHY Specific Control Reg */
+
+/*
+ * MARVELL 88E1111 PHY register bit masks
+ */
+/* PHY Specific Status Register (MV1111_EXT_CTRL1_REG) */
+
+#define SPEC_STAT_SPEED_MASK	(3 << 14)
+#define SPEC_STAT_FULL_DUP	(1 << 13)
+#define SPEC_STAT_PAGE_RCVD	(1 << 12)
+#define SPEC_STAT_RESOLVED	(1 << 11)	/* Speed and Duplex Resolved */
+#define SPEC_STAT_LINK_UP	(1 << 10)
+#define SPEC_STAT_CABLE_LEN_MASK	(7 << 7)/* Cable Length (100/1000 modes only) */
+#define SPEC_STAT_MDIX		(1 << 6)
+#define SPEC_STAT_POLARITY	(1 << 1)
+#define SPEC_STAT_JABBER	(1 << 0)
+
+#define SPEED_1000		(2 << 14)
+#define SPEED_100		(1 << 14)
+#define SPEED_10		(0 << 14)
+
+#define TBI_ADDR	0x1E	/* Ten Bit Interface address */
+
+/* negotiated link parameters */
+#define LINK_SPEED_UNKNOWN	0
+#define LINK_SPEED_10		1
+#define LINK_SPEED_100		2
+#define LINK_SPEED_1000		3
+
+#define LINK_DUPLEX_UNKNOWN	0
+#define LINK_DUPLEX_HALF	1
+#define LINK_DUPLEX_FULL	2
+
+static unsigned int phy_address[] = { 8, 9 };
+
+#define vuint32 volatile u32
+
+/* TX/RX buffer descriptors. MUST be cache line aligned in memory. (32 byte)
+ * This structure is accessed by the ethernet DMA engine which means it
+ * MUST be in LITTLE ENDIAN format */
+struct dma_descriptor {
+	vuint32 start_addr0;	/* buffer address, least significant bytes. */
+	vuint32 start_addr1;	/* buffer address, most significant bytes. */
+	vuint32 next_descr_addr0;/* next descriptor address, least significant bytes.  Must be 64-bit aligned. */
+	vuint32 next_descr_addr1;/* next descriptor address, most significant bytes. */
+	vuint32 vlan_byte_count;/* VLAN tag(top 2 bytes) and byte countt (bottom 2 bytes). */
+	vuint32 config_status;	/* Configuration/Status. */
+	vuint32 reserved1;	/* reserved to make the descriptor cache line aligned. */
+	vuint32 reserved2;	/* reserved to make the descriptor cache line aligned. */
+};
+
+/* last next descriptor address flag */
+#define DMA_DESCR_LAST		(1 << 31)
+
+/* TX DMA descriptor config status bits */
+#define DMA_DESCR_TX_EOF	(1 <<  0)	/* end of frame */
+#define DMA_DESCR_TX_SOF	(1 <<  1)	/* start of frame */
+#define DMA_DESCR_TX_PFVLAN	(1 <<  2)
+#define DMA_DESCR_TX_HUGE	(1 <<  3)
+#define DMA_DESCR_TX_PAD	(1 <<  4)
+#define DMA_DESCR_TX_CRC	(1 <<  5)
+#define DMA_DESCR_TX_DESCR_INT	(1 << 14)
+#define DMA_DESCR_TX_RETRY_COUNT	0x000F0000
+#define DMA_DESCR_TX_ONE_COLLISION	(1 << 20)
+#define DMA_DESCR_TX_LATE_COLLISION	(1 << 24)
+#define DMA_DESCR_TX_UNDERRUN		(1 << 25)
+#define DMA_DESCR_TX_RETRY_LIMIT	(1 << 26)
+#define DMA_DESCR_TX_OK			(1 << 30)
+#define DMA_DESCR_TX_OWNER		(1 << 31)
+
+/* RX DMA descriptor status bits */
+#define DMA_DESCR_RX_EOF		(1 <<  0)
+#define DMA_DESCR_RX_SOF		(1 <<  1)
+#define DMA_DESCR_RX_VTF		(1 <<  2)
+#define DMA_DESCR_RX_FRAME_IS_TYPE	(1 <<  3)
+#define DMA_DESCR_RX_SHORT_FRAME	(1 <<  4)
+#define DMA_DESCR_RX_HASH_MATCH		(1 <<  7)
+#define DMA_DESCR_RX_BAD_FRAME		(1 <<  8)
+#define DMA_DESCR_RX_OVERRUN		(1 <<  9)
+#define DMA_DESCR_RX_MAX_FRAME_LEN	(1 << 11)
+#define DMA_DESCR_RX_CRC_ERROR		(1 << 12)
+#define DMA_DESCR_RX_DESCR_INT		(1 << 13)
+#define DMA_DESCR_RX_OWNER		(1 << 15)
+
+#define RX_BUFFER_SIZE	PKTSIZE
+#define NUM_RX_DESC	PKTBUFSRX
+
+static struct dma_descriptor tx_descriptor __attribute__ ((aligned(32)));
+
+static struct dma_descriptor rx_descr_array[NUM_RX_DESC]
+	__attribute__ ((aligned(32)));
+
+static struct dma_descriptor *rx_descr_current;
+
+static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis);
+static int tsi108_eth_send (struct eth_device *dev,
+			   volatile void *packet, int length);
+static int tsi108_eth_recv (struct eth_device *dev);
+static void tsi108_eth_halt (struct eth_device *dev);
+static unsigned int read_phy (unsigned int base,
+			     unsigned int phy_addr, unsigned int phy_reg);
+static void write_phy (unsigned int base,
+		      unsigned int phy_addr,
+		      unsigned int phy_reg, unsigned int phy_data);
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print phy debug infomation
+ */
+static void dump_phy_regs (unsigned int phy_addr)
+{
+	int i;
+
+	printf ("PHY %d registers\n", phy_addr);
+	for (i = 0; i <= 30; i++) {
+		printf ("%2d  0x%04x\n", i, read_phy (ETH_BASE, phy_addr, i));
+	}
+	printf ("\n");
+
+}
+#else
+#define dump_phy_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void tx_diag_regs (unsigned int base)
+{
+	int i;
+	unsigned long dummy;
+
+	printf ("TX diagnostics registers\n");
+	reg_TX_DIAGNOSTIC_ADDR(base) = 0x00 | TX_DIAGNOSTIC_ADDR_AI;
+	udelay (1000);
+	dummy = reg_TX_DIAGNOSTIC_DATA(base);
+	for (i = 0x00; i <= 0x05; i++) {
+		udelay (1000);
+		printf ("0x%02x  0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base));
+	}
+	reg_TX_DIAGNOSTIC_ADDR(base) = 0x40 | TX_DIAGNOSTIC_ADDR_AI;
+	udelay (1000);
+	dummy = reg_TX_DIAGNOSTIC_DATA(base);
+	for (i = 0x40; i <= 0x47; i++) {
+		udelay (1000);
+		printf ("0x%02x  0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base));
+	}
+	printf ("\n");
+
+}
+#else
+#define tx_diag_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void rx_diag_regs (unsigned int base)
+{
+	int i;
+	unsigned long dummy;
+
+	printf ("RX diagnostics registers\n");
+	reg_RX_DIAGNOSTIC_ADDR(base) = 0x00 | RX_DIAGNOSTIC_ADDR_AI;
+	udelay (1000);
+	dummy = reg_RX_DIAGNOSTIC_DATA(base);
+	for (i = 0x00; i <= 0x05; i++) {
+		udelay (1000);
+		printf ("0x%02x  0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base));
+	}
+	reg_RX_DIAGNOSTIC_ADDR(base) = 0x40 | RX_DIAGNOSTIC_ADDR_AI;
+	udelay (1000);
+	dummy = reg_RX_DIAGNOSTIC_DATA(base);
+	for (i = 0x08; i <= 0x0a; i++) {
+		udelay (1000);
+		printf ("0x%02x  0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base));
+	}
+	printf ("\n");
+
+}
+#else
+#define rx_diag_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void debug_mii_regs (unsigned int base)
+{
+	printf ("MII_MGMT_CONFIG     0x%08x\n", reg_MII_MGMT_CONFIG(base));
+	printf ("MII_MGMT_COMMAND    0x%08x\n", reg_MII_MGMT_COMMAND(base));
+	printf ("MII_MGMT_ADDRESS    0x%08x\n", reg_MII_MGMT_ADDRESS(base));
+	printf ("MII_MGMT_CONTROL    0x%08x\n", reg_MII_MGMT_CONTROL(base));
+	printf ("MII_MGMT_STATUS     0x%08x\n", reg_MII_MGMT_STATUS(base));
+	printf ("MII_MGMT_INDICATORS 0x%08x\n", reg_MII_MGMT_INDICATORS(base));
+	printf ("\n");
+
+}
+#else
+#define debug_mii_regs(base) do{}while(0)
+#endif
+
+/*
+ * Wait until the phy bus is non-busy
+ */
+static void phy_wait (unsigned int base, unsigned int condition)
+{
+	int timeout;
+
+	timeout = 0;
+	while (reg_MII_MGMT_INDICATORS(base) & condition) {
+		udelay (10);
+		if (++timeout > 10000) {
+			printf ("ERROR: timeout waiting for phy bus (%d)\n",
+			       condition);
+			break;
+		}
+	}
+}
+
+/*
+ * read phy register
+ */
+static unsigned int read_phy (unsigned int base,
+			     unsigned int phy_addr, unsigned int phy_reg)
+{
+	unsigned int value;
+
+	phy_wait (base, MII_MGMT_INDICATORS_BUSY);
+
+	reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg;
+
+	/* Ensure that the Read Cycle bit is cleared prior to next read cycle */
+	reg_MII_MGMT_COMMAND(base) = 0;
+
+	/* start the read */
+	reg_MII_MGMT_COMMAND(base) = MII_MGMT_COMMAND_READ_CYCLE;
+
+	/* wait for the read to complete */
+	phy_wait (base,
+		 MII_MGMT_INDICATORS_NOT_VALID | MII_MGMT_INDICATORS_BUSY);
+
+	value = reg_MII_MGMT_STATUS(base);
+
+	reg_MII_MGMT_COMMAND(base) = 0;
+
+	return value;
+}
+
+/*
+ * write phy register
+ */
+static void write_phy (unsigned int base,
+		      unsigned int phy_addr,
+		      unsigned int phy_reg, unsigned int phy_data)
+{
+	phy_wait (base, MII_MGMT_INDICATORS_BUSY);
+
+	reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg;
+
+	/* Ensure that the Read Cycle bit is cleared prior to next cycle */
+	reg_MII_MGMT_COMMAND(base) = 0;
+
+	/* start the write */
+	reg_MII_MGMT_CONTROL(base) = phy_data;
+}
+
+/*
+ * configure the marvell 88e1111 phy
+ */
+static int marvell_88e_phy_config (struct eth_device *dev, int *speed,
+				  int *duplex)
+{
+	unsigned long base;
+	unsigned long phy_addr;
+	unsigned int phy_status;
+	unsigned int phy_spec_status;
+	int timeout;
+	int phy_speed;
+	int phy_duplex;
+	unsigned int value;
+
+	phy_speed = LINK_SPEED_UNKNOWN;
+	phy_duplex = LINK_DUPLEX_UNKNOWN;
+
+	base = dev->iobase;
+	phy_addr = (unsigned long)dev->priv;
+
+	/* Take the PHY out of reset. */
+	write_phy (ETH_BASE, phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
+
+	/* Wait for the reset process to complete. */
+	udelay (10);
+	timeout = 0;
+	while ((phy_status =
+		read_phy (ETH_BASE, phy_addr, PHY_CTRL_REG)) & PHY_CTRL_RESET) {
+		udelay (10);
+		if (++timeout > 10000) {
+			printf ("ERROR: timeout waiting for phy reset\n");
+			break;
+		}
+	}
+
+	/* TBI Configuration. */
+	write_phy (base, TBI_ADDR, TBI_CONTROL_2, TBI_CONTROL_2_G_MII_MODE |
+		  TBI_CONTROL_2_RECEIVE_CLOCK_SELECT);
+	/* Wait for the link to be established. */
+	timeout = 0;
+	do {
+		udelay (20000);
+		phy_status = read_phy (ETH_BASE, phy_addr, PHY_STATUS_REG);
+		if (++timeout > 100) {
+			debug_lev(1, "ERROR: unable to establish link!!!\n");
+			break;
+		}
+	} while ((phy_status & PHY_STAT_LINK_UP) == 0);
+
+	if ((phy_status & PHY_STAT_LINK_UP) == 0)
+		return 0;
+
+	value = 0;
+	phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG);
+	if (phy_spec_status & SPEC_STAT_RESOLVED) {
+		switch (phy_spec_status & SPEC_STAT_SPEED_MASK) {
+		case SPEED_1000:
+			phy_speed = LINK_SPEED_1000;
+			value |= PHY_CTRL_SPEED1;
+			break;
+		case SPEED_100:
+			phy_speed = LINK_SPEED_100;
+			value |= PHY_CTRL_SPEED0;
+			break;
+		case SPEED_10:
+			phy_speed = LINK_SPEED_10;
+			break;
+		}
+		if (phy_spec_status & SPEC_STAT_FULL_DUP) {
+			phy_duplex = LINK_DUPLEX_FULL;
+			value |= PHY_CTRL_FULL_DUPLEX;
+		} else
+			phy_duplex = LINK_DUPLEX_HALF;
+	}
+	/* set TBI speed */
+	write_phy (base, TBI_ADDR, PHY_CTRL_REG, value);
+	write_phy (base, TBI_ADDR, PHY_AN_ADV_REG, 0x0060);
+
+#if TSI108_ETH_DEBUG > 0
+	printf ("%s link is up", dev->name);
+	phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG);
+	if (phy_spec_status & SPEC_STAT_RESOLVED) {
+		switch (phy_speed) {
+		case LINK_SPEED_1000:
+			printf (", 1000 Mbps");
+			break;
+		case LINK_SPEED_100:
+			printf (", 100 Mbps");
+			break;
+		case LINK_SPEED_10:
+			printf (", 10 Mbps");
+			break;
+		}
+		if (phy_duplex == LINK_DUPLEX_FULL)
+			printf (", Full duplex");
+		else
+			printf (", Half duplex");
+	}
+	printf ("\n");
+#endif
+
+	dump_phy_regs (TBI_ADDR);
+	if (speed)
+		*speed = phy_speed;
+	if (duplex)
+		*duplex = phy_duplex;
+
+	return 1;
+}
+
+/*
+ * External interface
+ *
+ * register the tsi108 ethernet controllers with the multi-ethernet system
+ */
+int tsi108_eth_initialize (bd_t * bis)
+{
+	struct eth_device *dev;
+	int index;
+
+	for (index = 0; index < CONFIG_TSI108_ETH_NUM_PORTS; index++) {
+		dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+
+		sprintf (dev->name, "TSI108_eth%d", index);
+
+		dev->iobase = ETH_BASE + (index * ETH_PORT_OFFSET);
+		dev->priv = (void *)(phy_address[index]);
+		dev->init = tsi108_eth_probe;
+		dev->halt = tsi108_eth_halt;
+		dev->send = tsi108_eth_send;
+		dev->recv = tsi108_eth_recv;
+
+		eth_register(dev);
+	}
+	return index;
+}
+
+/*
+ * probe for and initialize a single ethernet interface
+ */
+static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis)
+{
+	unsigned long base;
+	unsigned long value;
+	int index;
+	struct dma_descriptor *tx_descr;
+	struct dma_descriptor *rx_descr;
+	int speed;
+	int duplex;
+
+	base = dev->iobase;
+
+	reg_PORT_CONTROL(base) = PORT_CONTROL_STE | PORT_CONTROL_BPT;
+
+	/* Bring DMA/FIFO out of reset. */
+	reg_TX_CONFIG(base) = 0x00000000;
+	reg_RX_CONFIG(base) = 0x00000000;
+
+	reg_TX_THRESHOLDS(base) = (192 << 16) | 192;
+	reg_RX_THRESHOLDS(base) = (192 << 16) | 112;
+
+	/* Bring MAC out of reset. */
+	reg_MAC_CONFIG_1(base) = 0x00000000;
+
+	/* DMA MAC configuration. */
+	reg_MAC_CONFIG_1(base) =
+	    MAC_CONFIG_1_RX_ENABLE | MAC_CONFIG_1_TX_ENABLE;
+
+	reg_MII_MGMT_CONFIG(base) = MII_MGMT_CONFIG_NO_PREAMBLE;
+	reg_MAXIMUM_FRAME_LENGTH(base) = RX_BUFFER_SIZE;
+
+	/* Note: Early tsi108 manual did not have correct byte order
+	 * for the station address.*/
+	reg_STATION_ADDRESS_1(base) = (dev->enetaddr[5] << 24) |
+	    (dev->enetaddr[4] << 16) |
+	    (dev->enetaddr[3] << 8) | (dev->enetaddr[2] << 0);
+
+	reg_STATION_ADDRESS_2(base) = (dev->enetaddr[1] << 24) |
+	    (dev->enetaddr[0] << 16);
+
+	if (marvell_88e_phy_config(dev, &speed, &duplex) == 0)
+		return 0;
+
+	value =
+	    MAC_CONFIG_2_PREAMBLE_LENGTH(7) | MAC_CONFIG_2_PAD_CRC |
+	    MAC_CONFIG_2_CRC_ENABLE;
+	if (speed == LINK_SPEED_1000)
+		value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_BYTE);
+	else {
+		value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_NIBBLE);
+		reg_PORT_CONTROL(base) |= PORT_CONTROL_SPD;
+	}
+	if (duplex == LINK_DUPLEX_FULL) {
+		value |= MAC_CONFIG_2_FULL_DUPLEX;
+		reg_PORT_CONTROL(base) &= ~PORT_CONTROL_BPT;
+	} else
+		reg_PORT_CONTROL(base) |= PORT_CONTROL_BPT;
+	reg_MAC_CONFIG_2(base) = value;
+
+	reg_RX_CONFIG(base) = RX_CONFIG_SE;
+	reg_RX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY;
+	reg_RX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY;
+
+	/* initialize the RX DMA descriptors */
+	rx_descr = &rx_descr_array[0];
+	rx_descr_current = rx_descr;
+	for (index = 0; index < NUM_RX_DESC; index++) {
+		/* make sure the receive buffers are not in cache */
+		invalidate_dcache_range((unsigned long)NetRxPackets[index],
+					(unsigned long)NetRxPackets[index] +
+					RX_BUFFER_SIZE);
+		rx_descr->start_addr0 =
+		    cpu_to_le32((vuint32) NetRxPackets[index]);
+		rx_descr->start_addr1 = 0;
+		rx_descr->next_descr_addr0 =
+		    cpu_to_le32((vuint32) (rx_descr + 1));
+		rx_descr->next_descr_addr1 = 0;
+		rx_descr->vlan_byte_count = 0;
+		rx_descr->config_status = cpu_to_le32((RX_BUFFER_SIZE << 16) |
+						      DMA_DESCR_RX_OWNER);
+		rx_descr++;
+	}
+	rx_descr--;
+	rx_descr->next_descr_addr0 = 0;
+	rx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+	/* Push the descriptors to RAM so the ethernet DMA can see them */
+	invalidate_dcache_range((unsigned long)rx_descr_array,
+				(unsigned long)rx_descr_array +
+				sizeof(rx_descr_array));
+
+	/* enable RX queue */
+	reg_RX_CONTROL(base) = TX_CONTROL_GO | 0x01;
+	reg_RX_QUEUE_0_PTR_LOW(base) = (u32) rx_descr_current;
+	/* enable receive DMA */
+	reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID;
+
+	reg_TX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY;
+	reg_TX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY;
+
+	/* initialize the TX DMA descriptor */
+	tx_descr = &tx_descriptor;
+
+	tx_descr->start_addr0 = 0;
+	tx_descr->start_addr1 = 0;
+	tx_descr->next_descr_addr0 = 0;
+	tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+	tx_descr->vlan_byte_count = 0;
+	tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OK |
+					      DMA_DESCR_TX_SOF |
+					      DMA_DESCR_TX_EOF);
+	/* enable TX queue */
+	reg_TX_CONTROL(base) = TX_CONTROL_GO | 0x01;
+
+	return 1;
+}
+
+/*
+ * send a packet
+ */
+static int tsi108_eth_send (struct eth_device *dev,
+			   volatile void *packet, int length)
+{
+	unsigned long base;
+	int timeout;
+	struct dma_descriptor *tx_descr;
+	unsigned long status;
+
+	base = dev->iobase;
+	tx_descr = &tx_descriptor;
+
+	/* Wait until the last packet has been transmitted. */
+	timeout = 0;
+	do {
+		/* make sure we see the changes made by the DMA engine */
+		invalidate_dcache_range((unsigned long)tx_descr,
+					(unsigned long)tx_descr +
+					sizeof(struct dma_descriptor));
+
+		if (timeout != 0)
+			udelay (15);
+		if (++timeout > 10000) {
+			tx_diag_regs(base);
+			debug_lev(1,
+				  "ERROR: timeout waiting for last transmit packet to be sent\n");
+			return 0;
+		}
+	} while (tx_descr->config_status & cpu_to_le32(DMA_DESCR_TX_OWNER));
+
+	status = le32_to_cpu(tx_descr->config_status);
+	if ((status & DMA_DESCR_TX_OK) == 0) {
+#ifdef TX_PRINT_ERRORS
+		printf ("TX packet error: 0x%08x\n    %s%s%s%s\n", status,
+		       status & DMA_DESCR_TX_OK ? "tx error, " : "",
+		       status & DMA_DESCR_TX_RETRY_LIMIT ?
+		       "retry limit reached, " : "",
+		       status & DMA_DESCR_TX_UNDERRUN ? "underrun, " : "",
+		       status & DMA_DESCR_TX_LATE_COLLISION ? "late collision, "
+		       : "");
+#endif
+	}
+
+	debug_lev (9, "sending packet %d\n", length);
+	tx_descr->start_addr0 = cpu_to_le32((vuint32) packet);
+	tx_descr->start_addr1 = 0;
+	tx_descr->next_descr_addr0 = 0;
+	tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+	tx_descr->vlan_byte_count = cpu_to_le32(length);
+	tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OWNER |
+					      DMA_DESCR_TX_CRC |
+					      DMA_DESCR_TX_PAD |
+					      DMA_DESCR_TX_SOF |
+					      DMA_DESCR_TX_EOF);
+
+	invalidate_dcache_range((unsigned long)tx_descr,
+				(unsigned long)tx_descr +
+				sizeof(struct dma_descriptor));
+
+	invalidate_dcache_range((unsigned long)packet,
+				(unsigned long)packet + length);
+
+	reg_TX_QUEUE_0_PTR_LOW(base) = (u32) tx_descr;
+	reg_TX_QUEUE_0_PTR_HIGH(base) = TX_QUEUE_0_PTR_HIGH_VALID;
+
+	return length;
+}
+
+/*
+ * Check for received packets and send them up the protocal stack
+ */
+static int tsi108_eth_recv (struct eth_device *dev)
+{
+	struct dma_descriptor *rx_descr;
+	unsigned long base;
+	int length = 0;
+	unsigned long status;
+	volatile uchar *buffer;
+
+	base = dev->iobase;
+
+	/* make sure we see the changes made by the DMA engine */
+	invalidate_dcache_range ((unsigned long)rx_descr_array,
+				(unsigned long)rx_descr_array +
+				sizeof(rx_descr_array));
+
+	/* process all of the received packets */
+	rx_descr = rx_descr_current;
+	while ((rx_descr->config_status & cpu_to_le32(DMA_DESCR_RX_OWNER)) == 0) {
+		/* check for error */
+		status = le32_to_cpu(rx_descr->config_status);
+		if (status & DMA_DESCR_RX_BAD_FRAME) {
+#ifdef RX_PRINT_ERRORS
+			printf ("RX packet error: 0x%08x\n    %s%s%s%s%s%s\n",
+			       status,
+			       status & DMA_DESCR_RX_FRAME_IS_TYPE ? "too big, "
+			       : "",
+			       status & DMA_DESCR_RX_SHORT_FRAME ? "too short, "
+			       : "",
+			       status & DMA_DESCR_RX_BAD_FRAME ? "bad frame, " :
+			       "",
+			       status & DMA_DESCR_RX_OVERRUN ? "overrun, " : "",
+			       status & DMA_DESCR_RX_MAX_FRAME_LEN ?
+			       "max length, " : "",
+			       status & DMA_DESCR_RX_CRC_ERROR ? "CRC error, " :
+			       "");
+#endif
+		} else {
+			length =
+			    le32_to_cpu(rx_descr->vlan_byte_count) & 0xFFFF;
+
+			/*** process packet ***/
+			buffer =
+			    (volatile uchar
+			     *)(le32_to_cpu (rx_descr->start_addr0));
+			NetReceive (buffer, length);
+
+			invalidate_dcache_range ((unsigned long)buffer,
+						(unsigned long)buffer +
+						RX_BUFFER_SIZE);
+		}
+		/* Give this buffer back to the DMA engine */
+		rx_descr->vlan_byte_count = 0;
+		rx_descr->config_status = cpu_to_le32 ((RX_BUFFER_SIZE << 16) |
+						      DMA_DESCR_RX_OWNER);
+		/* move descriptor pointer forward */
+		rx_descr =
+		    (struct dma_descriptor
+		     *)(le32_to_cpu (rx_descr->next_descr_addr0));
+		if (rx_descr == 0)
+			rx_descr = &rx_descr_array[0];
+	}
+	/* remember where we are for next time */
+	rx_descr_current = rx_descr;
+
+	/* If the DMA engine has reached the end of the queue
+	 * start over at the begining */
+	if (reg_RX_EXTENDED_STATUS(base) & RX_EXTENDED_STATUS_EOQ_0) {
+
+		reg_RX_EXTENDED_STATUS(base) = RX_EXTENDED_STATUS_EOQ_0;
+		reg_RX_QUEUE_0_PTR_LOW(base) = (u32) & rx_descr_array[0];
+		reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID;
+	}
+
+	return length;
+}
+
+/*
+ * disable an ethernet interface
+ */
+static void tsi108_eth_halt (struct eth_device *dev)
+{
+	unsigned long base;
+
+	base = dev->iobase;
+
+	/* Put DMA/FIFO into reset state. */
+	reg_TX_CONFIG(base) = TX_CONFIG_RST;
+	reg_RX_CONFIG(base) = RX_CONFIG_RST;
+
+	/* Put MAC into reset state. */
+	reg_MAC_CONFIG_1(base) = MAC_CONFIG_1_SOFT_RESET;
+}
+
+#endif
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
new file mode 100644
index 0000000..1267c57
--- /dev/null
+++ b/drivers/net/uli526x.c
@@ -0,0 +1,996 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Roy Zang <tie-fei.zang@freescale.com>, Sep, 2007
+ *
+ * Description:
+ * ULI 526x Ethernet port driver.
+ * Based on the Linux driver: drivers/net/tulip/uli526x.c
+ *
+ * This 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.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+/* some kernel function compatible define */
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+	defined(CONFIG_ULI526X)
+
+#undef DEBUG
+
+/* Board/System/Debug information/definition */
+#define ULI_VENDOR_ID		0x10B9
+#define ULI5261_DEVICE_ID	0x5261
+#define ULI5263_DEVICE_ID	0x5263
+/* ULi M5261 ID*/
+#define PCI_ULI5261_ID		ULI5261_DEVICE_ID << 16 | ULI_VENDOR_ID
+/* ULi M5263 ID*/
+#define PCI_ULI5263_ID		ULI5263_DEVICE_ID << 16 | ULI_VENDOR_ID
+
+#define ULI526X_IO_SIZE	0x100
+#define TX_DESC_CNT	0x10		/* Allocated Tx descriptors */
+#define RX_DESC_CNT	PKTBUFSRX	/* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT	(TX_DESC_CNT - 2) /* Max TX packet count */
+#define TX_WAKE_DESC_CNT	(TX_DESC_CNT - 3) /* TX wakeup count */
+#define DESC_ALL_CNT		(TX_DESC_CNT + RX_DESC_CNT)
+#define TX_BUF_ALLOC		0x300
+#define RX_ALLOC_SIZE		PKTSIZE
+#define ULI526X_RESET		1
+#define CR0_DEFAULT		0
+#define CR6_DEFAULT		0x22200000
+#define CR7_DEFAULT		0x180c1
+#define CR15_DEFAULT		0x06		/* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK		0x4302		/* TXJT, LC, EC, FUE */
+#define MAX_PACKET_SIZE		1514
+#define ULI5261_MAX_MULTICAST	14
+#define RX_COPY_SIZE		100
+#define MAX_CHECK_PACKET	0x8000
+
+#define ULI526X_10MHF		0
+#define ULI526X_100MHF		1
+#define ULI526X_10MFD		4
+#define ULI526X_100MFD		5
+#define ULI526X_AUTO		8
+
+#define ULI526X_TXTH_72		0x400000	/* TX TH 72 byte */
+#define ULI526X_TXTH_96		0x404000	/* TX TH 96 byte */
+#define ULI526X_TXTH_128	0x0000		/* TX TH 128 byte */
+#define ULI526X_TXTH_256	0x4000		/* TX TH 256 byte */
+#define ULI526X_TXTH_512	0x8000		/* TX TH 512 byte */
+#define ULI526X_TXTH_1K		0xC000		/* TX TH 1K  byte */
+
+/* CR9 definition: SROM/MII */
+#define CR9_SROM_READ		0x4800
+#define CR9_SRCS		0x1
+#define CR9_SRCLK		0x2
+#define CR9_CRDOUT		0x8
+#define SROM_DATA_0		0x0
+#define SROM_DATA_1		0x4
+#define PHY_DATA_1		0x20000
+#define PHY_DATA_0		0x00000
+#define MDCLKH			0x10000
+
+#define PHY_POWER_DOWN	0x800
+
+#define SROM_V41_CODE		0x14
+
+#define SROM_CLK_WRITE(data, ioaddr) do {			\
+	outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr);		\
+	udelay(5);						\
+	outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK, ioaddr);	\
+	udelay(5);						\
+	outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr);		\
+	udelay(5);						\
+	} while (0)
+
+/* Structure/enum declaration */
+
+struct tx_desc {
+	u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+	char *tx_buf_ptr;		/* Data for us */
+	struct tx_desc *next_tx_desc;
+};
+
+struct rx_desc {
+	u32 rdes0, rdes1, rdes2, rdes3;	/* Data for the card */
+	char *rx_buf_ptr;		/* Data for us */
+	struct rx_desc *next_rx_desc;
+};
+
+struct uli526x_board_info {
+	u32 chip_id;	/* Chip vendor/Device ID */
+	pci_dev_t pdev;
+
+	long ioaddr;			/* I/O base address */
+	u32 cr0_data;
+	u32 cr5_data;
+	u32 cr6_data;
+	u32 cr7_data;
+	u32 cr15_data;
+
+	/* pointer for memory physical address */
+	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
+	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
+	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
+	dma_addr_t first_tx_desc_dma;
+	dma_addr_t first_rx_desc_dma;
+
+	/* descriptor pointer */
+	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
+	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
+	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
+	struct tx_desc *first_tx_desc;
+	struct tx_desc *tx_insert_ptr;
+	struct tx_desc *tx_remove_ptr;
+	struct rx_desc *first_rx_desc;
+	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
+	unsigned long tx_packet_cnt;	/* transmitted packet count */
+
+	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
+
+	u8 media_mode;			/* user specify media mode */
+	u8 op_mode;			/* real work dedia mode */
+	u8 phy_addr;
+
+	/* NIC SROM data */
+	unsigned char srom[128];
+};
+
+enum uli526x_offsets {
+	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
+	DCR15 = 0x78
+};
+
+enum uli526x_CR6_bits {
+	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
+};
+
+/* Global variable declaration -- */
+
+static unsigned char uli526x_media_mode = ULI526X_AUTO;
+
+static struct tx_desc desc_pool_array[DESC_ALL_CNT + 0x20]
+	__attribute__ ((aligned(32)));
+static char buf_pool[TX_BUF_ALLOC * TX_DESC_CNT + 4];
+
+/* For module input parameter */
+static int mode = 8;
+
+/* function declaration -- */
+static int uli526x_start_xmit(struct eth_device *dev,
+				volatile void *packet, int length);
+static const struct ethtool_ops netdev_ethtool_ops;
+static u16 read_srom_word(long, int);
+static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
+static void allocate_rx_buffer(struct uli526x_board_info *);
+static void update_cr6(u32, unsigned long);
+static u16 phy_read(unsigned long, u8, u8, u32);
+static u16 phy_readby_cr10(unsigned long, u8, u8);
+static void phy_write(unsigned long, u8, u8, u16, u32);
+static void phy_writeby_cr10(unsigned long, u8, u8, u16);
+static void phy_write_1bit(unsigned long, u32, u32);
+static u16 phy_read_1bit(unsigned long, u32);
+static int uli526x_rx_packet(struct eth_device *);
+static void uli526x_free_tx_pkt(struct eth_device *,
+		struct uli526x_board_info *);
+static void uli526x_reuse_buf(struct rx_desc *);
+static void uli526x_init(struct eth_device *);
+static void uli526x_set_phyxcer(struct uli526x_board_info *);
+
+
+static int uli526x_init_one(struct eth_device *, bd_t *);
+static void uli526x_disable(struct eth_device *);
+static void set_mac_addr(struct eth_device *);
+
+static struct pci_device_id uli526x_pci_tbl[] = {
+	{ ULI_VENDOR_ID, ULI5261_DEVICE_ID}, /* 5261 device */
+	{ ULI_VENDOR_ID, ULI5263_DEVICE_ID}, /* 5263 device */
+	{}
+};
+
+/* ULI526X network board routine */
+
+/*
+ *	Search ULI526X board, register it
+ */
+
+int uli526x_initialize(bd_t *bis)
+{
+	pci_dev_t devno;
+	int card_number = 0;
+	struct eth_device *dev;
+	struct uli526x_board_info *db;	/* board information structure */
+
+	u32 iobase;
+	int idx = 0;
+
+	while (1) {
+		/* Find PCI device */
+		devno = pci_find_devices(uli526x_pci_tbl, idx++);
+		if (devno < 0)
+			break;
+
+		pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+		iobase &= ~0xf;
+
+		dev = (struct eth_device *)malloc(sizeof *dev);
+		sprintf(dev->name, "uli526x#%d\n", card_number);
+		db = (struct uli526x_board_info *)
+			malloc(sizeof(struct uli526x_board_info));
+
+		dev->priv = db;
+		db->pdev = devno;
+		dev->iobase = iobase;
+
+		dev->init = uli526x_init_one;
+		dev->halt = uli526x_disable;
+		dev->send = uli526x_start_xmit;
+		dev->recv = uli526x_rx_packet;
+
+		/* init db */
+		db->ioaddr = dev->iobase;
+		/* get chip id */
+
+		pci_read_config_dword(devno, PCI_VENDOR_ID, &db->chip_id);
+#ifdef DEBUG
+		printf("uli526x: uli526x @0x%x\n", iobase);
+		printf("uli526x: chip_id%x\n", db->chip_id);
+#endif
+		eth_register(dev);
+		card_number++;
+		pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
+		udelay(10 * 1000);
+	}
+	return card_number;
+}
+
+static int uli526x_init_one(struct eth_device *dev, bd_t *bis)
+{
+
+	struct uli526x_board_info *db = dev->priv;
+	int i;
+
+	switch (mode) {
+	case ULI526X_10MHF:
+	case ULI526X_100MHF:
+	case ULI526X_10MFD:
+	case ULI526X_100MFD:
+		uli526x_media_mode = mode;
+		break;
+	default:
+		uli526x_media_mode = ULI526X_AUTO;
+		break;
+	}
+
+	/* Allocate Tx/Rx descriptor memory */
+	db->desc_pool_ptr = (uchar *)&desc_pool_array[0];
+	db->desc_pool_dma_ptr = (dma_addr_t)&desc_pool_array[0];
+	if (db->desc_pool_ptr == NULL)
+		return 0;
+
+	db->buf_pool_ptr = &buf_pool[0];
+	db->buf_pool_dma_ptr = (dma_addr_t)&buf_pool[0];
+	if (db->buf_pool_ptr == NULL)
+		return 0;
+
+	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
+	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
+
+	db->buf_pool_start = db->buf_pool_ptr;
+	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
+
+#ifdef DEBUG
+	printf("%s(): db->ioaddr= 0x%x\n",
+		__FUNCTION__, db->ioaddr);
+	printf("%s(): media_mode= 0x%x\n",
+		__FUNCTION__, uli526x_media_mode);
+	printf("%s(): db->desc_pool_ptr= 0x%x\n",
+		__FUNCTION__, db->desc_pool_ptr);
+	printf("%s(): db->desc_pool_dma_ptr= 0x%x\n",
+		__FUNCTION__, db->desc_pool_dma_ptr);
+	printf("%s(): db->buf_pool_ptr= 0x%x\n",
+		__FUNCTION__, db->buf_pool_ptr);
+	printf("%s(): db->buf_pool_dma_ptr= 0x%x\n",
+		__FUNCTION__, db->buf_pool_dma_ptr);
+#endif
+
+	/* read 64 word srom data */
+	for (i = 0; i < 64; i++)
+		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr,
+			i));
+
+	/* Set Node address */
+	if (((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0)
+	/* SROM absent, so write MAC address to ID Table */
+		set_mac_addr(dev);
+	else {		/*Exist SROM*/
+		for (i = 0; i < 6; i++)
+			dev->enetaddr[i] = db->srom[20 + i];
+	}
+#ifdef DEBUG
+	for (i = 0; i < 6; i++)
+		printf("%c%02x", i ? ':' : ' ', dev->enetaddr[i]);
+#endif
+	db->PHY_reg4 = 0x1e0;
+
+	/* system variable init */
+	db->cr6_data = CR6_DEFAULT ;
+	db->cr6_data |= ULI526X_TXTH_256;
+	db->cr0_data = CR0_DEFAULT;
+	uli526x_init(dev);
+	return 1;
+}
+
+static void uli526x_disable(struct eth_device *dev)
+{
+#ifdef DEBUG
+	printf("uli526x_disable\n");
+#endif
+	struct uli526x_board_info *db = dev->priv;
+
+	if (!((inl(db->ioaddr + DCR12)) & 0x8)) {
+		/* Reset & stop ULI526X board */
+		outl(ULI526X_RESET, db->ioaddr + DCR0);
+		udelay(5);
+		phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+
+		/* reset the board */
+		db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
+		update_cr6(db->cr6_data, dev->iobase);
+		outl(0, dev->iobase + DCR7);		/* Disable Interrupt */
+		outl(inl(dev->iobase + DCR5), dev->iobase + DCR5);
+	}
+}
+
+/*	Initialize ULI526X board
+ *	Reset ULI526X board
+ *	Initialize TX/Rx descriptor chain structure
+ *	Send the set-up frame
+ *	Enable Tx/Rx machine
+ */
+
+static void uli526x_init(struct eth_device *dev)
+{
+
+	struct uli526x_board_info *db = dev->priv;
+	u8	phy_tmp;
+	u16	phy_value;
+	u16 phy_reg_reset;
+
+	/* Reset M526x MAC controller */
+	outl(ULI526X_RESET, db->ioaddr + DCR0);	/* RESET MAC */
+	udelay(100);
+	outl(db->cr0_data, db->ioaddr + DCR0);
+	udelay(5);
+
+	/* Phy addr : In some boards,M5261/M5263 phy address != 1 */
+	db->phy_addr = 1;
+	db->tx_packet_cnt = 0;
+	for (phy_tmp = 0; phy_tmp < 32; phy_tmp++) {
+		/* peer add */
+		phy_value = phy_read(db->ioaddr, phy_tmp, 3, db->chip_id);
+		if (phy_value != 0xffff && phy_value != 0) {
+			db->phy_addr = phy_tmp;
+			break;
+		}
+	}
+
+#ifdef DEBUG
+	printf("%s(): db->ioaddr= 0x%x\n", __FUNCTION__, db->ioaddr);
+	printf("%s(): db->phy_addr= 0x%x\n", __FUNCTION__, db->phy_addr);
+#endif
+	if (phy_tmp == 32)
+		printf("Can not find the phy address!!!");
+
+	/* Parser SROM and media mode */
+	db->media_mode = uli526x_media_mode;
+
+	if (!(inl(db->ioaddr + DCR12) & 0x8)) {
+		/* Phyxcer capability setting */
+		phy_reg_reset = phy_read(db->ioaddr,
+			db->phy_addr, 0, db->chip_id);
+		phy_reg_reset = (phy_reg_reset | 0x8000);
+		phy_write(db->ioaddr, db->phy_addr, 0,
+			phy_reg_reset, db->chip_id);
+		udelay(500);
+
+		/* Process Phyxcer Media Mode */
+		uli526x_set_phyxcer(db);
+	}
+	/* Media Mode Process */
+	if (!(db->media_mode & ULI526X_AUTO))
+		db->op_mode = db->media_mode; 	/* Force Mode */
+
+	/* Initialize Transmit/Receive decriptor and CR3/4 */
+	uli526x_descriptor_init(db, db->ioaddr);
+
+	/* Init CR6 to program M526X operation */
+	update_cr6(db->cr6_data, db->ioaddr);
+
+	/* Init CR7, interrupt active bit */
+	db->cr7_data = CR7_DEFAULT;
+	outl(db->cr7_data, db->ioaddr + DCR7);
+
+	/* Init CR15, Tx jabber and Rx watchdog timer */
+	outl(db->cr15_data, db->ioaddr + DCR15);
+
+	/* Enable ULI526X Tx/Rx function */
+	db->cr6_data |= CR6_RXSC | CR6_TXSC;
+	update_cr6(db->cr6_data, db->ioaddr);
+	while (!(inl(db->ioaddr + DCR12) & 0x8))
+		udelay(10);
+}
+
+/*
+ *	Hardware start transmission.
+ *	Send a packet to media from the upper layer.
+ */
+
+static int uli526x_start_xmit(struct eth_device *dev,
+				volatile void *packet, int length)
+{
+	struct uli526x_board_info *db = dev->priv;
+	struct tx_desc *txptr;
+	unsigned int len = length;
+	/* Too large packet check */
+	if (len > MAX_PACKET_SIZE) {
+		printf(": big packet = %d\n", len);
+		return 0;
+	}
+
+	/* No Tx resource check, it never happen nromally */
+	if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
+		printf("No Tx resource %ld\n", db->tx_packet_cnt);
+		return 0;
+	}
+
+	/* Disable NIC interrupt */
+	outl(0, dev->iobase + DCR7);
+
+	/* transmit this packet */
+	txptr = db->tx_insert_ptr;
+	memcpy((char *)txptr->tx_buf_ptr, (char *)packet, (int)length);
+	txptr->tdes1 = cpu_to_le32(0xe1000000 | length);
+
+	/* Point to next transmit free descriptor */
+	db->tx_insert_ptr = txptr->next_tx_desc;
+
+	/* Transmit Packet Process */
+	if ((db->tx_packet_cnt < TX_DESC_CNT)) {
+		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
+		db->tx_packet_cnt++;			/* Ready to send */
+		outl(0x1, dev->iobase + DCR1);	/* Issue Tx polling */
+	}
+
+	/* Got ULI526X status */
+	db->cr5_data = inl(db->ioaddr + DCR5);
+	outl(db->cr5_data, db->ioaddr + DCR5);
+
+#ifdef TX_DEBUG
+	printf("%s(): length = 0x%x\n", __FUNCTION__, length);
+	printf("%s(): cr5_data=%x\n", __FUNCTION__, db->cr5_data);
+#endif
+
+	outl(db->cr7_data, dev->iobase + DCR7);
+	uli526x_free_tx_pkt(dev, db);
+
+	return length;
+}
+
+/*
+ *	Free TX resource after TX complete
+ */
+
+static void uli526x_free_tx_pkt(struct eth_device *dev,
+	struct uli526x_board_info *db)
+{
+	struct tx_desc *txptr;
+	u32 tdes0;
+
+	txptr = db->tx_remove_ptr;
+	while (db->tx_packet_cnt) {
+		tdes0 = le32_to_cpu(txptr->tdes0);
+		/* printf(DRV_NAME ": tdes0=%x\n", tdes0); */
+		if (tdes0 & 0x80000000)
+			break;
+
+		/* A packet sent completed */
+		db->tx_packet_cnt--;
+
+		if (tdes0 != 0x7fffffff) {
+#ifdef TX_DEBUG
+			printf("%s()tdes0=%x\n", __FUNCTION__, tdes0);
+#endif
+			if (tdes0 & TDES0_ERR_MASK) {
+				if (tdes0 & 0x0002) {	/* UnderRun */
+					if (!(db->cr6_data & CR6_SFT)) {
+						db->cr6_data = db->cr6_data |
+							CR6_SFT;
+						update_cr6(db->cr6_data,
+							db->ioaddr);
+					}
+				}
+			}
+		}
+
+		txptr = txptr->next_tx_desc;
+	}/* End of while */
+
+	/* Update TX remove pointer to next */
+	db->tx_remove_ptr = txptr;
+}
+
+
+/*
+ *	Receive the come packet and pass to upper layer
+ */
+
+static int uli526x_rx_packet(struct eth_device *dev)
+{
+	struct uli526x_board_info *db = dev->priv;
+	struct rx_desc *rxptr;
+	int rxlen = 0;
+	u32 rdes0;
+
+	rxptr = db->rx_ready_ptr;
+
+	rdes0 = le32_to_cpu(rxptr->rdes0);
+#ifdef RX_DEBUG
+	printf("%s(): rxptr->rdes0=%x:%x\n", __FUNCTION__, rxptr->rdes0);
+#endif
+	if (!(rdes0 & 0x80000000)) {	/* packet owner check */
+		if ((rdes0 & 0x300) != 0x300) {
+			/* A packet without First/Last flag */
+			/* reuse this buf */
+			printf("A packet without First/Last flag");
+			uli526x_reuse_buf(rxptr);
+		} else {
+			/* A packet with First/Last flag */
+			rxlen = ((rdes0 >> 16) & 0x3fff) - 4;
+#ifdef RX_DEBUG
+			printf("%s(): rxlen =%x\n", __FUNCTION__, rxlen);
+#endif
+			/* error summary bit check */
+			if (rdes0 & 0x8000) {
+				/* This is a error packet */
+				printf("Eroor: rdes0: %lx\n", rdes0);
+			}
+
+			if (!(rdes0 & 0x8000) ||
+				((db->cr6_data & CR6_PM) && (rxlen > 6))) {
+
+#ifdef RX_DEBUG
+				printf("%s(): rx_skb_ptr =%x\n",
+					__FUNCTION__, rxptr->rx_buf_ptr);
+				printf("%s(): rxlen =%x\n",
+					__FUNCTION__, rxlen);
+
+				printf("%s(): buf addr =%x\n",
+					__FUNCTION__, rxptr->rx_buf_ptr);
+				printf("%s(): rxlen =%x\n",
+					__FUNCTION__, rxlen);
+				int i;
+				for (i = 0; i < 0x20; i++)
+					printf("%s(): data[%x] =%x\n",
+					__FUNCTION__, i, rxptr->rx_buf_ptr[i]);
+#endif
+
+				NetReceive(rxptr->rx_buf_ptr, rxlen);
+				uli526x_reuse_buf(rxptr);
+
+			} else {
+				/* Reuse SKB buffer when the packet is error */
+				printf("Reuse buffer, rdes0");
+				uli526x_reuse_buf(rxptr);
+			}
+		}
+
+		rxptr = rxptr->next_rx_desc;
+	}
+
+	db->rx_ready_ptr = rxptr;
+	return rxlen;
+}
+
+/*
+ *	Reuse the RX buffer
+ */
+
+static void uli526x_reuse_buf(struct rx_desc *rxptr)
+{
+
+	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000)))
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
+	else
+		printf("Buffer reuse method error");
+}
+/*
+ *	Initialize transmit/Receive descriptor
+ *	Using Chain structure, and allocate Tx/Rx buffer
+ */
+
+static void uli526x_descriptor_init(struct uli526x_board_info *db,
+	unsigned long ioaddr)
+{
+	struct tx_desc *tmp_tx;
+	struct rx_desc *tmp_rx;
+	unsigned char *tmp_buf;
+	dma_addr_t tmp_tx_dma, tmp_rx_dma;
+	dma_addr_t tmp_buf_dma;
+	int i;
+	/* tx descriptor start pointer */
+	db->tx_insert_ptr = db->first_tx_desc;
+	db->tx_remove_ptr = db->first_tx_desc;
+
+	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
+
+	/* rx descriptor start pointer */
+	db->first_rx_desc = (void *)db->first_tx_desc +
+		sizeof(struct tx_desc) * TX_DESC_CNT;
+	db->first_rx_desc_dma =  db->first_tx_desc_dma +
+		sizeof(struct tx_desc) * TX_DESC_CNT;
+	db->rx_ready_ptr = db->first_rx_desc;
+	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */
+#ifdef DEBUG
+	printf("%s(): db->first_tx_desc= 0x%x\n",
+		__FUNCTION__, db->first_tx_desc);
+	printf("%s(): db->first_rx_desc_dma= 0x%x\n",
+		__FUNCTION__, db->first_rx_desc_dma);
+#endif
+	/* Init Transmit chain */
+	tmp_buf = db->buf_pool_start;
+	tmp_buf_dma = db->buf_pool_dma_start;
+	tmp_tx_dma = db->first_tx_desc_dma;
+	for (tmp_tx = db->first_tx_desc, i = 0;
+			i < TX_DESC_CNT; i++, tmp_tx++) {
+		tmp_tx->tx_buf_ptr = tmp_buf;
+		tmp_tx->tdes0 = cpu_to_le32(0);
+		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
+		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
+		tmp_tx_dma += sizeof(struct tx_desc);
+		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
+		tmp_tx->next_tx_desc = tmp_tx + 1;
+		tmp_buf = tmp_buf + TX_BUF_ALLOC;
+		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
+	}
+	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
+	tmp_tx->next_tx_desc = db->first_tx_desc;
+
+	 /* Init Receive descriptor chain */
+	tmp_rx_dma = db->first_rx_desc_dma;
+	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT;
+			i++, tmp_rx++) {
+		tmp_rx->rdes0 = cpu_to_le32(0);
+		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
+		tmp_rx_dma += sizeof(struct rx_desc);
+		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
+		tmp_rx->next_rx_desc = tmp_rx + 1;
+	}
+	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
+	tmp_rx->next_rx_desc = db->first_rx_desc;
+
+	/* pre-allocate Rx buffer */
+	allocate_rx_buffer(db);
+}
+
+/*
+ *	Update CR6 value
+ *	Firstly stop ULI526X, then written value and start
+ */
+
+static void update_cr6(u32 cr6_data, unsigned long ioaddr)
+{
+
+	outl(cr6_data, ioaddr + DCR6);
+	udelay(5);
+}
+
+/*
+ *	Allocate rx buffer,
+ */
+
+static void allocate_rx_buffer(struct uli526x_board_info *db)
+{
+	int index;
+	struct rx_desc *rxptr;
+	rxptr = db->first_rx_desc;
+	u32 addr;
+
+	for (index = 0; index < RX_DESC_CNT; index++) {
+		addr = (u32)NetRxPackets[index];
+		addr += (16 - (addr & 15));
+		rxptr->rx_buf_ptr = (char *) addr;
+		rxptr->rdes2 = cpu_to_le32(addr);
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
+#ifdef DEBUG
+		printf("%s(): Number 0x%x:\n", __FUNCTION__, index);
+		printf("%s(): addr 0x%x:\n", __FUNCTION__, addr);
+		printf("%s(): rxptr address = 0x%x\n", __FUNCTION__, rxptr);
+		printf("%s(): rxptr buf address = 0x%x\n", \
+			__FUNCTION__, rxptr->rx_buf_ptr);
+		printf("%s(): rdes2  = 0x%x\n", __FUNCTION__, rxptr->rdes2);
+#endif
+		rxptr = rxptr->next_rx_desc;
+	}
+}
+
+/*
+ *	Read one word data from the serial ROM
+ */
+
+static u16 read_srom_word(long ioaddr, int offset)
+{
+	int i;
+	u16 srom_data = 0;
+	long cr9_ioaddr = ioaddr + DCR9;
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	/* Send the Read Command 110b */
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
+
+	/* Send the offset */
+	for (i = 5; i >= 0; i--) {
+		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
+		SROM_CLK_WRITE(srom_data, cr9_ioaddr);
+	}
+
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	for (i = 16; i > 0; i--) {
+		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
+		udelay(5);
+		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT)
+			? 1 : 0);
+		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+		udelay(5);
+	}
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	return srom_data;
+}
+
+/*
+ *	Set 10/100 phyxcer capability
+ *	AUTO mode : phyxcer register4 is NIC capability
+ *	Force mode: phyxcer register4 is the force media
+ */
+
+static void uli526x_set_phyxcer(struct uli526x_board_info *db)
+{
+	u16 phy_reg;
+
+	/* Phyxcer capability setting */
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+	if (db->media_mode & ULI526X_AUTO) {
+		/* AUTO Mode */
+		phy_reg |= db->PHY_reg4;
+	} else {
+		/* Force Mode */
+		switch (db->media_mode) {
+		case ULI526X_10MHF: phy_reg |= 0x20; break;
+		case ULI526X_10MFD: phy_reg |= 0x40; break;
+		case ULI526X_100MHF: phy_reg |= 0x80; break;
+		case ULI526X_100MFD: phy_reg |= 0x100; break;
+		}
+
+	}
+
+	/* Write new capability to Phyxcer Reg4 */
+	if (!(phy_reg & 0x01e0)) {
+		phy_reg |= db->PHY_reg4;
+		db->media_mode |= ULI526X_AUTO;
+	}
+	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+	/* Restart Auto-Negotiation */
+	phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+	udelay(50);
+}
+
+/*
+ *	Write a word to Phy register
+ */
+
+static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
+	u16 phy_data, u32 chip_id)
+{
+	u16 i;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_ULI5263_ID) {
+		phy_writeby_cr10(iobase, phy_addr, offset, phy_data);
+		return;
+	}
+	/* M5261/M5263 Chip */
+	ioaddr = iobase + DCR9;
+
+	/* Send 33 synchronization clock to Phy controller */
+	for (i = 0; i < 35; i++)
+		phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+	/* Send start command(01) to Phy */
+	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+	/* Send write command(01) to Phy */
+	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+	/* Send Phy address */
+	for (i = 0x10; i > 0; i = i >> 1)
+		phy_write_1bit(ioaddr, phy_addr & i ?
+			PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+	/* Send register address */
+	for (i = 0x10; i > 0; i = i >> 1)
+		phy_write_1bit(ioaddr, offset & i ?
+			PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+	/* written trasnition */
+	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+	/* Write a word data to PHY controller */
+	for (i = 0x8000; i > 0; i >>= 1)
+		phy_write_1bit(ioaddr, phy_data & i ?
+			PHY_DATA_1 : PHY_DATA_0, chip_id);
+}
+
+/*
+ *	Read a word data from phy register
+ */
+
+static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
+{
+	int i;
+	u16 phy_data;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_ULI5263_ID)
+		return phy_readby_cr10(iobase, phy_addr, offset);
+	/* M5261/M5263 Chip */
+	ioaddr = iobase + DCR9;
+
+	/* Send 33 synchronization clock to Phy controller */
+	for (i = 0; i < 35; i++)
+		phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+	/* Send start command(01) to Phy */
+	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+	/* Send read command(10) to Phy */
+	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+	/* Send Phy address */
+	for (i = 0x10; i > 0; i = i >> 1)
+		phy_write_1bit(ioaddr, phy_addr & i ?
+			PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+	/* Send register address */
+	for (i = 0x10; i > 0; i = i >> 1)
+		phy_write_1bit(ioaddr, offset & i ?
+			PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+	/* Skip transition state */
+	phy_read_1bit(ioaddr, chip_id);
+
+	/* read 16bit data */
+	for (phy_data = 0, i = 0; i < 16; i++) {
+		phy_data <<= 1;
+		phy_data |= phy_read_1bit(ioaddr, chip_id);
+	}
+
+	return phy_data;
+}
+
+static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
+{
+	unsigned long ioaddr, cr10_value;
+
+	ioaddr = iobase + DCR10;
+	cr10_value = phy_addr;
+	cr10_value = (cr10_value<<5) + offset;
+	cr10_value = (cr10_value<<16) + 0x08000000;
+	outl(cr10_value, ioaddr);
+	udelay(1);
+	while (1) {
+		cr10_value = inl(ioaddr);
+		if (cr10_value & 0x10000000)
+			break;
+	}
+	return (cr10_value&0x0ffff);
+}
+
+static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr,
+	u8 offset, u16 phy_data)
+{
+	unsigned long ioaddr, cr10_value;
+
+	ioaddr = iobase + DCR10;
+	cr10_value = phy_addr;
+	cr10_value = (cr10_value<<5) + offset;
+	cr10_value = (cr10_value<<16) + 0x04000000 + phy_data;
+	outl(cr10_value, ioaddr);
+	udelay(1);
+}
+/*
+ *	Write one bit data to Phy Controller
+ */
+
+static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id)
+{
+	outl(phy_data , ioaddr);			/* MII Clock Low */
+	udelay(1);
+	outl(phy_data  | MDCLKH, ioaddr);	/* MII Clock High */
+	udelay(1);
+	outl(phy_data , ioaddr);			/* MII Clock Low */
+	udelay(1);
+}
+
+/*
+ *	Read one bit phy data from PHY controller
+ */
+
+static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
+{
+	u16 phy_data;
+
+	outl(0x50000 , ioaddr);
+	udelay(1);
+	phy_data = (inl(ioaddr) >> 19) & 0x1;
+	outl(0x40000 , ioaddr);
+	udelay(1);
+
+	return phy_data;
+}
+
+/*
+ * Set MAC address to ID Table
+ */
+
+static void set_mac_addr(struct eth_device *dev)
+{
+	int i;
+	u16 addr;
+	struct uli526x_board_info *db = dev->priv;
+	outl(0x10000, db->ioaddr + DCR0);	/* Diagnosis mode */
+	/* Reset dianostic pointer port */
+	outl(0x1c0, db->ioaddr + DCR13);
+	outl(0, db->ioaddr + DCR14);	/* Clear reset port */
+	outl(0x10, db->ioaddr + DCR14);	/* Reset ID Table pointer */
+	outl(0, db->ioaddr + DCR14);	/* Clear reset port */
+	outl(0, db->ioaddr + DCR13);	/* Clear CR13 */
+	/* Select ID Table access port */
+	outl(0x1b0, db->ioaddr + DCR13);
+	/* Read MAC address from CR14 */
+	for (i = 0; i < 3; i++) {
+		addr = dev->enetaddr[2 * i] | (dev->enetaddr[2 * i + 1] << 8);
+		outl(addr, db->ioaddr + DCR14);
+	}
+	/* write end */
+	outl(0, db->ioaddr + DCR13);	/* Clear CR13 */
+	outl(0, db->ioaddr + DCR0);	/* Clear CR0 */
+	udelay(10);
+	return;
+}
+#endif