## Automatically generated incremental diff
## From:   linux-2.4.23-bk1
## To:     linux-2.4.23-bk2
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.23-bk1/Makefile linux-2.4.23-bk2/Makefile
--- linux-2.4.23-bk1/Makefile	2003-12-03 02:49:49.000000000 -0800
+++ linux-2.4.23-bk2/Makefile	2003-12-03 02:49:51.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 23
-EXTRAVERSION = -bk1
+EXTRAVERSION = -bk2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -175,7 +175,6 @@
 DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
-DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
 DRIVERS-$(CONFIG_VT) += drivers/video/video.o
 DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
 DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
@@ -221,6 +220,7 @@
 	drivers/scsi/aic7xxx/aicasm/aicdb.h \
 	drivers/scsi/aic7xxx/aicasm/y.tab.h \
 	drivers/scsi/53c700_d.h \
+	drivers/tc/lk201-map.c \
 	net/khttpd/make_times_h \
 	net/khttpd/times.h \
 	submenu*
diff -urN linux-2.4.23-bk1/crypto/api.c linux-2.4.23-bk2/crypto/api.c
--- linux-2.4.23-bk1/crypto/api.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.23-bk2/crypto/api.c	2003-12-03 02:49:51.000000000 -0800
@@ -37,6 +37,9 @@
 struct crypto_alg *crypto_alg_lookup(const char *name)
 {
 	struct crypto_alg *q, *alg = NULL;
+
+	if (!name)
+		return NULL;
 	
 	down_read(&crypto_alg_sem);
 	
diff -urN linux-2.4.23-bk1/drivers/char/drm/drm_agpsupport.h linux-2.4.23-bk2/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.23-bk1/drivers/char/drm/drm_agpsupport.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/char/drm/drm_agpsupport.h	2003-12-03 02:49:51.000000000 -0800
@@ -79,7 +79,7 @@
 		return -EBUSY;
 	if(!drm_agp->acquire)
 		return -EINVAL;
-	if (retcode = drm_agp->acquire())
+	if ((retcode = drm_agp->acquire()))
 		return retcode;
 	dev->agp->acquired = 1;
 	return 0;
diff -urN linux-2.4.23-bk1/drivers/char/drm/drm_os_linux.h linux-2.4.23-bk2/drivers/char/drm/drm_os_linux.h
--- linux-2.4.23-bk1/drivers/char/drm/drm_os_linux.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/char/drm/drm_os_linux.h	2003-12-03 02:49:51.000000000 -0800
@@ -13,12 +13,10 @@
 		return -EFAULT
 
 
-#warning the author of this code needs to read up on list_entry
 #define DRM_GETSAREA()							 \
 do { 									 \
-	struct list_head *list;						 \
-	list_for_each( list, &dev->maplist->head ) {			 \
-		drm_map_list_t *entry = (drm_map_list_t *)list;		 \
+	drm_map_list_t *entry;						 \
+	list_for_each_entry( entry, &dev->maplist->head, head ) {	 \
 		if ( entry->map &&					 \
 		     entry->map->type == _DRM_SHM &&			 \
 		     (entry->map->flags & _DRM_CONTAINS_LOCK) ) {	 \
diff -urN linux-2.4.23-bk1/drivers/char/drm/radeon_drv.h linux-2.4.23-bk2/drivers/char/drm/radeon_drv.h
--- linux-2.4.23-bk1/drivers/char/drm/radeon_drv.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/char/drm/radeon_drv.h	2003-12-03 02:49:51.000000000 -0800
@@ -839,14 +839,6 @@
  * Ring control
  */
 
-#if defined(__powerpc__)
-#define radeon_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
-#else
-#define radeon_flush_write_combine()	wmb()
-#warning PCI posting bug
-#endif
-
-
 #define RADEON_VERBOSE	0
 
 #define RING_LOCALS	int write, _nr; unsigned int mask; u32 *ring;
diff -urN linux-2.4.23-bk1/drivers/net/Config.in linux-2.4.23-bk2/drivers/net/Config.in
--- linux-2.4.23-bk1/drivers/net/Config.in	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/Config.in	2003-12-03 02:49:52.000000000 -0800
@@ -59,21 +59,24 @@
    if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
       tristate '  MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
    fi
+   if [ "$CONFIG_MOMENCO_OCELOT_G" = "y" ]; then
+      bool '  GT-64240 Ethernet support' CONFIG_GALILEO_64240_ETH
+   fi
    if [ "$CONFIG_MIPS_GT96100" = "y" ]; then
       bool '  MIPS GT96100 Ethernet support' CONFIG_MIPS_GT96100ETH
    fi
-   if [ "$CONFIG_MIPS_AU1000" = "y" ]; then
-      bool '  MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET
+   if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+      tristate '  MIPS Au1x00 Ethernet support' CONFIG_MIPS_AU1X00_ENET
+      if [ "$CONFIG_MIPS_AU1X00_ENET" = "y" ]; then
+         bool '   Broadcom 5222 Dual Phy Support' CONFIG_BCM5222_DUAL_PHY
+      fi
    fi
-   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+   if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
       tristate '  SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
    fi
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
-   if [ "$CONFIG_SGI_IP32" = "y" ]; then
-      tristate '  SGI O2 MACE Fast Ethernet support' CONFIG_SGI_O2MACE_ETH
-   fi
    if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
@@ -211,7 +214,7 @@
          tristate '    TI ThunderLAN support' CONFIG_TLAN
       fi
       if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
-         dep_tristate '    TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI
+	 dep_tristate '    TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI
       fi
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_mbool '      Use MMIO instead of PIO (EXPERIMENTAL)' CONFIG_VIA_RHINE_MMIO $CONFIG_VIA_RHINE $CONFIG_EXPERIMENTAL
@@ -232,7 +235,7 @@
       dep_tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620 $CONFIG_ISA
    fi
    if [ "$CONFIG_SGI_IP22" = "y" ]; then
-      bool '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
+      tristate '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
    fi
    if [ "$CONFIG_DECSTATION" = "y" ]; then
       tristate '  DEC LANCE ethernet controller support' CONFIG_DECLANCE
diff -urN linux-2.4.23-bk1/drivers/net/Makefile linux-2.4.23-bk2/drivers/net/Makefile
--- linux-2.4.23-bk1/drivers/net/Makefile	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/Makefile	2003-12-03 02:49:52.000000000 -0800
@@ -115,6 +115,7 @@
 # end link order section
 #
 
+obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
 obj-$(CONFIG_MV64340_ETH)	+= mv64340_eth.o
 obj-$(CONFIG_AIRONET4500) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_CS) 	+= aironet4500_core.o
@@ -176,7 +177,6 @@
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
-obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
 obj-$(CONFIG_AT1700) += at1700.o
 obj-$(CONFIG_FMV18X) += fmv18x.o
 obj-$(CONFIG_EL1) += 3c501.o
@@ -219,7 +219,7 @@
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
-obj-$(CONFIG_MIPS_AU1000_ENET) += au1000_eth.o
+obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_BAGETLANCE) += bagetlance.o
 obj-$(CONFIG_DECLANCE) += declance.o
diff -urN linux-2.4.23-bk1/drivers/net/Space.c linux-2.4.23-bk2/drivers/net/Space.c
--- linux-2.4.23-bk1/drivers/net/Space.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.23-bk2/drivers/net/Space.c	2003-12-03 02:49:52.000000000 -0800
@@ -83,7 +83,6 @@
 extern int SK_init(struct net_device *);
 extern int seeq8005_probe(struct net_device *);
 extern int smc_init( struct net_device * );
-extern int sgiseeq_probe(struct net_device *);
 extern int atarilance_probe(struct net_device *);
 extern int sun3lance_probe(struct net_device *);
 extern int sun3_82586_probe(struct net_device *);
@@ -366,14 +365,6 @@
 	{NULL, 0},
 };
 
-
-static struct devprobe sgi_probes[] __initdata = {
-#ifdef CONFIG_SGISEEQ
-	{sgiseeq_probe, 0},
-#endif
-	{NULL, 0},
-};
-
 static struct devprobe mips_probes[] __initdata = {
 #ifdef CONFIG_MIPS_JAZZ_SONIC
 	{sonic_probe, 0},
@@ -408,8 +399,6 @@
 		return 0;
 	if (probe_list(dev, mips_probes) == 0)
 		return 0;
-	if (probe_list(dev, sgi_probes) == 0)
-		return 0;
 	if (probe_list(dev, eisa_probes) == 0)
 		return 0;
 	if (probe_list(dev, mca_probes) == 0)
diff -urN linux-2.4.23-bk1/drivers/net/au1000_eth.c linux-2.4.23-bk2/drivers/net/au1000_eth.c
--- linux-2.4.23-bk1/drivers/net/au1000_eth.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/au1000_eth.c	2003-12-03 02:49:52.000000000 -0800
@@ -1,8 +1,9 @@
 /*
  *
- * Alchemy Semi Au1000 ethernet driver
+ * Alchemy Au1x00 ethernet driver
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2002 TimeSys Corp.
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
@@ -22,8 +23,15 @@
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
  * ########################################################################
+ *
+ * 
  */
-#include <linux/config.h>
+
+#ifndef __mips__
+#error This driver only works with MIPS architectures!
+#endif
+
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -44,22 +52,27 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/processor.h>
 
 #include <asm/au1000.h>
+#include <asm/cpu.h>
 #include "au1000_eth.h"
 
+
 #ifdef AU1000_ETH_DEBUG
-static int au1000_debug = 10;
+static int au1000_debug = 5;
 #else
 static int au1000_debug = 3;
 #endif
 
+MODULE_LICENSE("GPL");
+
 // prototypes
 static void *dma_alloc(size_t, dma_addr_t *);
 static void dma_free(void *, size_t);
 static void hard_stop(struct net_device *);
 static void enable_rx_tx(struct net_device *dev);
-static int __init au1000_probe1(struct net_device *, long, int, int);
+static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
 static int au1000_init(struct net_device *);
 static int au1000_open(struct net_device *);
 static int au1000_close(struct net_device *);
@@ -101,27 +114,8 @@
  */
 
 
-/*
- * Base address and interupt of the Au1xxx ethernet macs
- */
-static struct {
-	unsigned int port;
-	int irq;
-} au1000_iflist[NUM_INTERFACES] = {
-		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 
-		{AU1000_ETH1_BASE, AU1000_ETH1_IRQ}
-	},
-  au1500_iflist[NUM_INTERFACES] = {
-		{AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, 
-		{AU1500_ETH1_BASE, AU1000_ETH1_IRQ}
-	},
-  au1100_iflist[NUM_INTERFACES] = {
-		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 
-		{NULL, NULL}
-	};
-
 static char version[] __devinitdata =
-    "au1000eth.c:1.0 ppopov@mvista.com\n";
+    "au1000eth.c:1.4 ppopov@mvista.com\n";
 
 /* These addresses are only used if yamon doesn't tell us what
  * the mac address is, and the mac address is not passed on the
@@ -138,6 +132,7 @@
 #define cpu_to_dma32 cpu_to_be32
 #define dma32_to_cpu be32_to_cpu
 
+struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 
 /* FIXME 
  * All of the PHY code really should be detached from the MAC 
@@ -156,7 +151,6 @@
 	s16 data;
 	
 	/* Stop auto-negotiation */
-	//printk("bcm_5201_init\n");
 	data = mdio_read(dev, phy_addr, MII_CONTROL);
 	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
 
@@ -171,12 +165,8 @@
 	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
 	mdio_write(dev, phy_addr, MII_CONTROL, data);
 
-	/* Enable TX LED instead of FDX */
-	data = mdio_read(dev, phy_addr, MII_INT);
-	data &= ~MII_FDX_LED;
-	mdio_write(dev, phy_addr, MII_INT, data);
-
-	if (au1000_debug > 4) dump_mii(dev, phy_addr);
+	if (au1000_debug > 4) 
+		dump_mii(dev, phy_addr);
 	return 0;
 }
 
@@ -184,7 +174,6 @@
 {
 	s16 mii_control, timeout;
 	
-	//printk("bcm_5201_reset\n");
 	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
 	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
 	mdelay(1);
@@ -247,8 +236,8 @@
 		printk("lsi_80227_init\n");
 
 	/* restart auto-negotiation */
-	mdio_write(dev, phy_addr, 0, 0x3200);
-
+	mdio_write(dev, phy_addr, MII_CONTROL,
+		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); // | MII_CNTL_FDX);
 	mdelay(1);
 
 	/* set up LEDs to correct display */
@@ -299,9 +288,9 @@
 	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
 	if (mii_data & MII_STAT_LINK) {
 		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT);
-		if (mii_data & MII_LSI_STAT_SPD) {
-			if (mii_data & MII_LSI_STAT_FDX) {
+		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_PHY_STAT);
+		if (mii_data & MII_LSI_PHY_STAT_SPD) {
+			if (mii_data & MII_LSI_PHY_STAT_FDX) {
 				*speed = IF_PORT_100BASEFX;
 				dev->if_port = IF_PORT_100BASEFX;
 			}
@@ -342,12 +331,303 @@
 	return 0;
 }
 
+int am79c874_init(struct net_device *dev, int phy_addr)
+{
+	s16 data;
+
+	/* 79c874 has quit resembled bit assignments to BCM5201 */
+	if (au1000_debug > 4)
+		printk("am79c847_init\n");
+
+	/* Stop auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
+
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
+
+	if (au1000_debug > 4) dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int am79c874_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	if (au1000_debug > 4)
+		printk("am79c874_reset\n");
+
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int 
+am79c874_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	// printk("am79c874_status\n");
+	if (!dev) {
+		printk(KERN_ERR "am79c874_status error: NULL dev\n");
+		return -1;
+	}
+
+	aup = (struct au1000_private *) dev->priv;
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_AMD_PHY_STAT);
+		if (mii_data & MII_AMD_PHY_STAT_SPD) {
+			if (mii_data & MII_AMD_PHY_STAT_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int lxt971a_init(struct net_device *dev, int phy_addr)
+{
+	if (au1000_debug > 4)
+		printk("lxt971a_init\n");
+
+	/* restart auto-negotiation */
+	mdio_write(dev, phy_addr, MII_CONTROL,
+		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO | MII_CNTL_FDX);
+
+	/* set up LEDs to correct display */
+	mdio_write(dev, phy_addr, 20, 0x0422);
+
+	if (au1000_debug > 4)
+		dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int lxt971a_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	if (au1000_debug > 4) {
+		printk("lxt971a_reset\n");
+		dump_mii(dev, phy_addr);
+	}
+
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int
+lxt971a_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "lxt971a_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_INTEL_PHY_STAT);
+		if (mii_data & MII_INTEL_PHY_STAT_SPD) {
+			if (mii_data & MII_INTEL_PHY_STAT_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+int ks8995m_init(struct net_device *dev, int phy_addr)
+{
+	s16 data;
+	
+//	printk("ks8995m_init\n");
+	/* Stop auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
+
+	if (au1000_debug > 4) dump_mii(dev, phy_addr);
+
+	return 0;
+}
+
+int ks8995m_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+//	printk("ks8995m_reset\n");
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int ks8995m_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "ks8995m_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
+		if (mii_data & MII_AUX_100) {
+			if (mii_data & MII_AUX_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {											
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+		dev->if_port = IF_PORT_UNKNOWN;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_MIPS_BOSPORUS
+int stub_init(struct net_device *dev, int phy_addr)
+{
+	//printk("PHY stub_init\n");
+	return 0;
+}
+
+int stub_reset(struct net_device *dev, int phy_addr)
+{
+	//printk("PHY stub_reset\n");
+	return 0;
+}
+
+int 
+stub_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	//printk("PHY stub_status\n");
+	*link = 1;
+	/* hmmm, revisit */
+	*speed = IF_PORT_100BASEFX;
+	dev->if_port = IF_PORT_100BASEFX;
+	return 0;
+}
+#endif
+
 struct phy_ops bcm_5201_ops = {
 	bcm_5201_init,
 	bcm_5201_reset,
 	bcm_5201_status,
 };
 
+struct phy_ops am79c874_ops = {
+	am79c874_init,
+	am79c874_reset,
+	am79c874_status,
+};
+
 struct phy_ops am79c901_ops = {
 	am79c901_init,
 	am79c901_reset,
@@ -360,26 +640,82 @@
 	lsi_80227_status,
 };
 
+struct phy_ops lxt971a_ops = { 
+	lxt971a_init,
+	lxt971a_reset,
+	lxt971a_status,
+};
+
+struct phy_ops ks8995m_ops = {
+	ks8995m_init,
+	ks8995m_reset,
+	ks8995m_status,
+};
+
+#ifdef CONFIG_MIPS_BOSPORUS
+struct phy_ops stub_ops = {
+	stub_init,
+	stub_reset,
+	stub_status,
+};
+#endif
+
 static struct mii_chip_info {
 	const char * name;
 	u16 phy_id0;
 	u16 phy_id1;
 	struct phy_ops *phy_ops;	
+	int dual_phy;
 } mii_chip_table[] = {
-	{"Broadcom BCM5201 10/100 BaseT PHY",  0x0040, 0x6212, &bcm_5201_ops },
-	{"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8, &am79c901_ops },
-	{"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops },
-	{"Broadcom BCM5221 10/100 BaseT PHY",  0x0040, 0x61e4, &bcm_5201_ops },
+	{"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
+	{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
+	{"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
+	{"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
+	{"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
+	{"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
+	{"Intel LXT971A Dual Speed PHY",0x0013,0x78e2, &lxt971a_ops,0},
+	{"Kendin KS8995M 10/100 BaseT PHY",0x0022,0x1450, &ks8995m_ops,0},
+#ifdef CONFIG_MIPS_BOSPORUS
+	{"Stub", 0x1234, 0x5678, &stub_ops },
+#endif
 	{0,},
 };
 
 static int mdio_read(struct net_device *dev, int phy_id, int reg)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	volatile u32 *mii_control_reg;
+	volatile u32 *mii_data_reg;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	/* First time we probe, it's for the mac0 phy.
+	 * Since we haven't determined yet that we have a dual phy,
+	 * aup->mii->mii_control_reg won't be setup and we'll
+	 * default to the else statement.
+	 * By the time we probe for the mac1 phy, the mii_control_reg
+	 * will be setup to be the address of the mac0 phy control since
+	 * both phys are controlled through mac0.
+	 */
+	if (aup->mii && aup->mii->mii_control_reg) {
+		mii_control_reg = aup->mii->mii_control_reg;
+		mii_data_reg = aup->mii->mii_data_reg;
+	}
+	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+		/* assume both phys are controlled through mac0 */
+		mii_control_reg = au_macs[0]->mii->mii_control_reg;
+		mii_data_reg = au_macs[0]->mii->mii_data_reg;
+	}
+	else 
+	#endif
+	{
+		/* default control and data reg addresses */
+		mii_control_reg = &aup->mac->mii_control;
+		mii_data_reg = &aup->mac->mii_data;
+	}
+
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: read_MII busy timeout!!\n", 
@@ -391,10 +727,10 @@
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;
 
-	aup->mac->mii_control = mii_control;
+	*mii_control_reg = mii_control;
 
 	timedout = 20;
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: mdio_read busy timeout!!\n", 
@@ -402,16 +738,36 @@
 			return -1;
 		}
 	}
-	return (int)aup->mac->mii_data;
+	return (int)*mii_data_reg;
 }
 
 static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	volatile u32 *mii_control_reg;
+	volatile u32 *mii_data_reg;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	while (aup->mac->mii_control & MAC_MII_BUSY) {
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	if (aup->mii && aup->mii->mii_control_reg) {
+		mii_control_reg = aup->mii->mii_control_reg;
+		mii_data_reg = aup->mii->mii_data_reg;
+	}
+	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+		/* assume both phys are controlled through mac0 */
+		mii_control_reg = au_macs[0]->mii->mii_control_reg;
+		mii_data_reg = au_macs[0]->mii->mii_data_reg;
+	}
+	else 
+	#endif
+	{
+		/* default control and data reg addresses */
+		mii_control_reg = &aup->mac->mii_control;
+		mii_data_reg = &aup->mac->mii_data;
+	}
+
+	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
 			printk(KERN_ERR "%s: mdio_write busy timeout!!\n", 
@@ -423,8 +779,8 @@
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;
 
-	aup->mac->mii_data = value;
-	aup->mac->mii_control = mii_control;
+	*mii_data_reg = value;
+	*mii_control_reg = mii_control;
 }
 
 
@@ -442,12 +798,13 @@
 	}
 }
 
-static int __init mii_probe (struct net_device * dev)
+static int mii_probe (struct net_device * dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 	int phy_addr;
-
-	aup->mii = NULL;
+#ifdef CONFIG_MIPS_BOSPORUS
+	int phy_found=0;
+#endif
 
 	/* search for total of 32 possible mii phy addresses */
 	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
@@ -455,6 +812,14 @@
 		u16 phy_id0, phy_id1;
 		int i;
 
+		#ifdef CONFIG_BCM5222_DUAL_PHY
+		/* Mask the already found phy, try next one */
+		if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
+			if (au_macs[0]->phy_addr == phy_addr)
+				continue;
+		}
+		#endif
+
 		mii_status = mdio_read(dev, phy_addr, MII_STATUS);
 		if (mii_status == 0xffff || mii_status == 0x0000)
 			/* the mii is not accessable, try next one */
@@ -467,6 +832,65 @@
 		for (i = 0; mii_chip_table[i].phy_id1; i++) {
 			if (phy_id0 == mii_chip_table[i].phy_id0 &&
 			    phy_id1 == mii_chip_table[i].phy_id1) {
+				struct mii_phy * mii_phy = aup->mii;
+
+				printk(KERN_INFO "%s: %s at phy address %d\n",
+				       dev->name, mii_chip_table[i].name, 
+				       phy_addr);
+#ifdef CONFIG_MIPS_BOSPORUS
+				phy_found = 1;
+#endif
+				mii_phy->chip_info = mii_chip_table+i;
+				aup->phy_addr = phy_addr;
+				aup->phy_ops = mii_chip_table[i].phy_ops;
+				aup->phy_ops->phy_init(dev,phy_addr);
+
+				// Check for dual-phy and then store required 
+				// values and set indicators. We need to do 
+				// this now since mdio_{read,write} need the 
+				// control and data register addresses.
+				#ifdef CONFIG_BCM5222_DUAL_PHY
+				if ( mii_chip_table[i].dual_phy) {
+
+					/* assume both phys are controlled 
+					 * through MAC0. Board specific? */
+					
+					/* sanity check */
+					if (!au_macs[0] || !au_macs[0]->mii)
+						return -1;
+					aup->mii->mii_control_reg = (u32 *)
+						&au_macs[0]->mac->mii_control;
+					aup->mii->mii_data_reg = (u32 *)
+						&au_macs[0]->mac->mii_data;
+				}
+				#endif
+				goto found;
+			}
+		}
+	}
+found:
+
+#ifdef CONFIG_MIPS_BOSPORUS
+	/* This is a workaround for the Micrel/Kendin 5 port switch
+	   The second MAC doesn't see a PHY connected... so we need to
+	   trick it into thinking we have one.
+		
+	   If this kernel is run on another Au1500 development board
+	   the stub will be found as well as the actual PHY. However,
+	   the last found PHY will be used... usually at Addr 31 (Db1500).	
+	*/
+	if ( (!phy_found) )
+	{
+		u16 phy_id0, phy_id1;
+		int i;
+
+		phy_id0 = 0x1234;
+		phy_id1 = 0x5678;
+
+		/* search our mii table for the current mii */ 
+		for (i = 0; mii_chip_table[i].phy_id1; i++) {
+			if (phy_id0 == mii_chip_table[i].phy_id0 &&
+			    phy_id1 == mii_chip_table[i].phy_id1) {
 				struct mii_phy * mii_phy;
 
 				printk(KERN_INFO "%s: %s at phy address %d\n",
@@ -476,31 +900,39 @@
 						GFP_KERNEL);
 				if (mii_phy) {
 					mii_phy->chip_info = mii_chip_table+i;
-					mii_phy->phy_addr = phy_addr;
+					aup->phy_addr = phy_addr;
 					mii_phy->next = aup->mii;
 					aup->phy_ops = 
 						mii_chip_table[i].phy_ops;
 					aup->mii = mii_phy;
 					aup->phy_ops->phy_init(dev,phy_addr);
 				} else {
-					printk(KERN_ERR "%s: out of memory\n",
+					printk(KERN_ERR "%s: out of memory\n", 
 							dev->name);
 					return -1;
 				}
-				/* the current mii is on our mii_info_table,
-				   try next address */
+				mii_phy->chip_info = mii_chip_table+i;
+				aup->phy_addr = phy_addr;
+				aup->phy_ops = mii_chip_table[i].phy_ops;
+				aup->phy_ops->phy_init(dev,phy_addr);
 				break;
 			}
 		}
 	}
+	if (aup->mac_id == 0) {
+		/* the Bosporus phy responds to addresses 0-5 but 
+		 * 5 is the correct one.
+		 */
+		aup->phy_addr = 5;
+	}
+#endif
 
 	if (aup->mii == NULL) {
-		printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name);
+		printk(KERN_ERR "%s: Au1x No MII transceivers found!\n",
+				dev->name);
 		return -1;
 	}
 
-	/* use last PHY */
-	aup->phy_addr = aup->mii->phy_addr;
 	printk(KERN_INFO "%s: Using %s as default\n", 
 			dev->name, aup->mii->chip_info->name);
 
@@ -521,7 +953,6 @@
 	if (pDB) {
 		aup->pDBfree = pDB->pnext;
 	}
-	//printk("GetFreeDB: %x\n", pDB);
 	return pDB;
 }
 
@@ -587,6 +1018,7 @@
 
 static void reset_mac(struct net_device *dev)
 {
+	int i;
 	u32 flags;
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 
@@ -597,11 +1029,27 @@
 	spin_lock_irqsave(&aup->lock, flags);
 	del_timer(&aup->timer);
 	hard_stop(dev);
-	*aup->enable = MAC_EN_CLOCK_ENABLE;
-	au_sync_delay(2);
-       	*aup->enable = 0;
-	au_sync_delay(2);
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	if (aup->mac_id != 0) {
+	#endif
+		/* If BCM5222, we can't leave MAC0 in reset because then 
+		 * we can't access the dual phy for ETH1 */
+		*aup->enable = MAC_EN_CLOCK_ENABLE;
+		au_sync_delay(2);
+		*aup->enable = 0;
+		au_sync_delay(2);
+	#ifdef CONFIG_BCM5222_DUAL_PHY
+	}
+	#endif
 	aup->tx_full = 0;
+	for (i = 0; i < NUM_RX_DMA; i++) {
+		/* reset control bits */
+		aup->rx_dma_ring[i]->buff_stat &= ~0xf;
+	}
+	for (i = 0; i < NUM_TX_DMA; i++) {
+		/* reset control bits */
+		aup->tx_dma_ring[i]->buff_stat &= ~0xf;
+	}
 	spin_unlock_irqrestore(&aup->lock, flags);
 }
 
@@ -616,95 +1064,110 @@
 {
 	int i;
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		aup->rx_dma_ring[i] = 
 			(volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
 	}
-	for (i=0; i<NUM_TX_DMA; i++) {
+	for (i = 0; i < NUM_TX_DMA; i++) {
 		aup->tx_dma_ring[i] = 
 			(volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
 	}
 }
 
+static struct {
+	int port;
+	u32 base_addr;
+	int irq;
+	struct net_device *dev;
+} iflist[2];
+
+static int num_ifs;
+
+/*
+ * Setup the base address and interupt of the Au1xxx ethernet macs
+ * based on cpu type and whether the interface is enabled in sys_pinfunc
+ * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
+ */
 static int __init au1000_init_module(void)
 {
-	int i;
-	int prid;
-	int base_addr, irq;
-
-	prid = read_32bit_cp0_register(CP0_PRID);
-	for (i=0; i<NUM_INTERFACES; i++) {
-		if ( (prid & 0xffff0000) == 0x00030000 ) {
-			base_addr = au1000_iflist[i].port;
-			irq = au1000_iflist[i].irq;
-		} else if ( (prid & 0xffff0000) == 0x01030000 ) {
-			base_addr = au1500_iflist[i].port;
-			irq = au1500_iflist[i].irq;
-		} else if ( (prid & 0xffff0000) == 0x02030000 ) {
-			base_addr = au1100_iflist[i].port;
-			irq = au1100_iflist[i].irq;
-		} else {
-			printk(KERN_ERR "au1000 eth: unknown Processor ID\n");
-			return -ENODEV;
-		}
-		// check for valid entries, au1100 only has one entry
-		if (base_addr && irq) {
-		if (au1000_probe1(NULL, base_addr, irq, i) != 0) {
-			return -ENODEV;
-		}
+	struct cpuinfo_mips *c = &current_cpu_data;
+	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
+	struct net_device *dev;
+	int i, found_one = 0;
+
+	iflist[0].irq = AU1000_ETH0_IRQ;
+	iflist[1].irq = AU1000_ETH1_IRQ;
+	switch (c->cputype) {
+	case CPU_AU1000:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1000_ETH0_BASE;
+		iflist[1].base_addr = AU1000_ETH1_BASE;
+		break;
+	case CPU_AU1100:
+		num_ifs = 1 - ni;
+		iflist[0].base_addr = AU1000_ETH0_BASE;
+		break;
+	case CPU_AU1500:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1500_ETH0_BASE;
+		iflist[1].base_addr = AU1500_ETH1_BASE;
+		break;
+	default:
+		num_ifs = 0;
 	}
+	for(i = 0; i < num_ifs; i++) {
+		dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
+		iflist[i].dev = dev;
+		if (dev)
+			found_one++;
 	}
+	if (!found_one)
+		return -ENODEV;
 	return 0;
 }
 
-static int __init
-au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num)
+static struct net_device *
+au1000_probe(u32 ioaddr, int irq, int port_num)
 {
 	static unsigned version_printed = 0;
 	struct au1000_private *aup = NULL;
-	int i, retval = 0;
+	struct net_device *dev = NULL;
 	db_dest_t *pDB, *pDBfree;
 	char *pmac, *argptr;
 	char ethaddr[6];
+	int i, err;
 
-	if (!request_region(ioaddr, MAC_IOSIZE, "Au1000 ENET")) {
-		 return -ENODEV;
-	}
+	if (!request_region(ioaddr, MAC_IOSIZE, "Au1x00 ENET"))
+		return NULL;
 
-	if (version_printed++ == 0) printk(version);
+	if (version_printed++ == 0) 
+		printk(version);
 
+	dev = alloc_etherdev(sizeof(struct au1000_private));
 	if (!dev) {
-		dev = init_etherdev(0, sizeof(struct au1000_private));
+		printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");  
+		return NULL;
 	}
-	if (!dev) {
-		 printk (KERN_ERR "au1000 eth: init_etherdev failed\n");  
-		 return -ENODEV;
+
+	if ((err = register_netdev(dev))) {
+		printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
+				err);
+		kfree(dev);
+		return NULL;
 	}
 
-	printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", 
+	printk("%s: Au1x Ethernet found at 0x%x, irq %d\n", 
 			dev->name, ioaddr, irq);
 
-	/* Initialize our private structure */
-	if (dev->priv == NULL) {
-		aup = (struct au1000_private *) 
-			kmalloc(sizeof(*aup), GFP_KERNEL);
-		if (aup == NULL) {
-			retval = -ENOMEM;
-			goto free_region;
-		}
-		dev->priv = aup;
-	}
-
 	aup = dev->priv;
-	memset(aup, 0, sizeof(*aup));
-
 
 	/* Allocate the data buffers */
 	aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * 
 			(NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr);
 	if (!aup->vaddr) {
-		retval = -ENOMEM;
-		goto free_region;
+		kfree(dev);
+		release_region(ioaddr, MAC_IOSIZE);
+		return NULL;
 	}
 
 	/* aup->mac is the base address of the MAC's registers */
@@ -737,7 +1200,10 @@
 				((unsigned long)AU1500_MAC0_ENABLE);
 		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
 		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
+		aup->mac_id = 0;
+		au_macs[0] = aup;
 			break;
+
 	case AU1000_ETH1_BASE:
 	case AU1500_ETH1_BASE:
 		if (ioaddr == AU1000_ETH1_BASE)
@@ -749,15 +1215,16 @@
 		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr));
 		dev->dev_addr[4] += 0x10;
 		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
+		aup->mac_id = 1;
+		au_macs[1] = aup;
 			break;
+
 	default:
 		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
 		break;
 
 	}
 
-	aup->phy_addr = PHY_ADDRESS;
-
 	/* bring the device out of reset, otherwise probing the mii
 	 * will hang */
 	*aup->enable = MAC_EN_CLOCK_ENABLE;
@@ -766,14 +1233,22 @@
 		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
 	au_sync_delay(2);
 
+	aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
+	if (!aup->mii) {
+		printk(KERN_ERR "%s: out of memory\n", dev->name);
+		goto err_out;
+	}
+	aup->mii->mii_control_reg = 0;
+	aup->mii->mii_data_reg = 0;
+
 	if (mii_probe(dev) != 0) {
-		 goto free_region;
+		goto err_out;
 	}
 
 	pDBfree = NULL;
 	/* setup the data buffer descriptors and attach a buffer to each one */
 	pDB = aup->db;
-	for (i=0; i<(NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
+	for (i = 0; i < (NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
 		pDB->pnext = pDBfree;
 		pDBfree = pDB;
 		pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i);
@@ -782,15 +1257,19 @@
 	}
 	aup->pDBfree = pDBfree;
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto free_region;
+		if (!pDB) {
+			goto err_out;
+		}
 		aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
 		aup->rx_db_inuse[i] = pDB;
 	}
-	for (i=0; i<NUM_TX_DMA; i++) {
+	for (i = 0; i < NUM_TX_DMA; i++) {
 		pDB = GetFreeDB(aup);
-		if (!pDB) goto free_region;
+		if (!pDB) {
+			goto err_out;
+		}
 		aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
 		aup->tx_dma_ring[i]->len = 0;
 		aup->tx_db_inuse[i] = pDB;
@@ -809,32 +1288,36 @@
 	dev->tx_timeout = au1000_tx_timeout;
 	dev->watchdog_timeo = ETH_TX_TIMEOUT;
 
-
-	/* Fill in the fields of the device structure with ethernet values. */
-	ether_setup(dev);
-
 	/* 
 	 * The boot code uses the ethernet controller, so reset it to start 
 	 * fresh.  au1000_init() expects that the device is in reset state.
 	 */
 	reset_mac(dev);
-	return 0;
 
-free_region:
-	release_region(ioaddr, MAC_IOSIZE);
+	return dev;
+
+err_out:
+	/* here we should have a valid dev plus aup-> register addresses
+	 * so we can reset the mac properly.*/
+	reset_mac(dev);
+	if (aup->mii)
+		kfree(aup->mii);
+	for (i = 0; i < NUM_RX_DMA; i++) {
+		if (aup->rx_db_inuse[i])
+			ReleaseDB(aup, aup->rx_db_inuse[i]);
+	}
+	for (i = 0; i < NUM_TX_DMA; i++) {
+		if (aup->tx_db_inuse[i])
+			ReleaseDB(aup, aup->tx_db_inuse[i]);
+	}
+	dma_free((void *)aup->vaddr, MAX_BUF_SIZE * 
+			(NUM_TX_BUFFS+NUM_RX_BUFFS));
 	unregister_netdev(dev);
-	if (aup->vaddr) 
-		dma_free((void *)aup->vaddr, 
-				MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));
-	if (dev->priv != NULL)
-		kfree(dev->priv);
-	printk(KERN_ERR "%s: au1000_probe1 failed.  Returns %d\n",
-	       dev->name, retval);
 	kfree(dev);
-	return retval;
+	release_region(ioaddr, MAC_IOSIZE);
+	return NULL;
 }
 
-
 /* 
  * Initialize the interface.
  *
@@ -852,7 +1335,8 @@
 	u32 control;
 	u16 link, speed;
 
-	if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name);
+	if (au1000_debug > 4) 
+		printk("%s: au1000_init\n", dev->name);
 
 	spin_lock_irqsave(&aup->lock, flags);
 
@@ -872,7 +1356,7 @@
 	aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
 		dev->dev_addr[1]<<8 | dev->dev_addr[0];
 
-	for (i=0; i<NUM_RX_DMA; i++) {
+	for (i = 0; i < NUM_RX_DMA; i++) {
 		aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
 	}
 	au_sync();
@@ -992,24 +1476,48 @@
 	if (au1000_debug > 4)
 		printk("%s: close: dev=%p\n", dev->name, dev);
 
+	reset_mac(dev);
+
 	spin_lock_irqsave(&aup->lock, flags);
 	
 	/* stop the device */
-	if (netif_device_present(dev)) {
-		netif_stop_queue(dev);
-	}
+	netif_stop_queue(dev);
 
 	/* disable the interrupt */
 	free_irq(dev->irq, dev);
 	spin_unlock_irqrestore(&aup->lock, flags);
 
-	reset_mac(dev);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static void __exit au1000_cleanup_module(void)
 {
+	int i, j;
+	struct net_device *dev;
+	struct au1000_private *aup;
+
+	for (i = 0; i < num_ifs; i++) {
+		dev = iflist[i].dev;
+		if (dev) {
+			aup = (struct au1000_private *) dev->priv;
+			unregister_netdev(dev);
+			if (aup->mii)
+				kfree(aup->mii);
+			for (j = 0; j < NUM_RX_DMA; j++) {
+				if (aup->rx_db_inuse[j])
+					ReleaseDB(aup, aup->rx_db_inuse[j]);
+			}
+			for (j = 0; j < NUM_TX_DMA; j++) {
+				if (aup->tx_db_inuse[j])
+					ReleaseDB(aup, aup->tx_db_inuse[j]);
+			}
+			dma_free((void *)aup->vaddr, MAX_BUF_SIZE * 
+					(NUM_TX_BUFFS+NUM_RX_BUFFS));
+			kfree(dev);
+			release_region(iflist[i].base_addr, MAC_IOSIZE);
+		}
+	}
 }
 
 
@@ -1081,7 +1589,7 @@
 	db_dest_t *pDB;
 	int i;
 
-	if (au1000_debug > 4)
+	if (au1000_debug > 5)
 		printk("%s: tx: aup %x len=%d, data=%p, head %d\n", 
 				dev->name, (unsigned)aup, skb->len, 
 				skb->data, aup->tx_head);
@@ -1106,11 +1614,11 @@
 
 	pDB = aup->tx_db_inuse[aup->tx_head];
 	memcpy((void *)pDB->vaddr, skb->data, skb->len);
-	if (skb->len < MAC_MIN_PKT_SIZE) {
-		for (i=skb->len; i<MAC_MIN_PKT_SIZE; i++) { 
+	if (skb->len < ETH_ZLEN) {
+		for (i=skb->len; i<ETH_ZLEN; i++) { 
 			((char *)pDB->vaddr)[i] = 0;
 		}
-		ptxd->len = MAC_MIN_PKT_SIZE;
+		ptxd->len = ETH_ZLEN;
 	}
 	else
 		ptxd->len = skb->len;
@@ -1159,8 +1667,9 @@
 	volatile rx_dma_t *prxd;
 	u32 buff_stat, status;
 	db_dest_t *pDB;
+	u32	frmlen;
 
-	if (au1000_debug > 4)
+	if (au1000_debug > 5)
 		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
 
 	prxd = aup->rx_dma_ring[aup->rx_head];
@@ -1172,7 +1681,9 @@
 		if (!(status & RX_ERROR))  {
 
 			/* good frame */
-			skb = dev_alloc_skb((status & RX_FRAME_LEN_MASK) + 2);
+			frmlen = (status & RX_FRAME_LEN_MASK);
+			frmlen -= 4; /* Remove FCS */
+			skb = dev_alloc_skb(frmlen + 2);
 			if (skb == NULL) {
 				printk(KERN_ERR
 				       "%s: Memory squeeze, dropping packet.\n",
@@ -1182,9 +1693,9 @@
 			}
 			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte IP header align */
-			eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, 
-					status & RX_FRAME_LEN_MASK, 0);
-			skb_put(skb, status & RX_FRAME_LEN_MASK);
+			eth_copy_and_sum(skb,
+				(unsigned char *)pDB->vaddr, frmlen, 0);
+			skb_put(skb, frmlen);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);	/* pass the packet to upper layers */
 		}
@@ -1236,8 +1747,11 @@
 		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
 		return;
 	}
-	au1000_tx_ack(dev);
+
+	/* Handle RX interrupts first to minimize chance of overrun */
+
 	au1000_rx(dev);
+	au1000_tx_ack(dev);
 }
 
 
@@ -1250,6 +1764,8 @@
 	printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);
 	reset_mac(dev);
 	au1000_init(dev);
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
 }
 
 
@@ -1305,27 +1821,19 @@
 
 static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	u16 *data = (u16 *)&rq->ifr_data;
+	//u16 *data = (u16 *)&rq->ifr_data;
 
 	/* fixme */
-	switch (cmd) { 
-	case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
-	case SIOCDEVPRIVATE:		/* binary compat, remove in 2.5 */
-		data[0] = PHY_ADDRESS;
-
-	case SIOCGMIIREG:		/* Read the specified MII register. */
-	case SIOCDEVPRIVATE+1:		/* binary compat, remove in 2.5 */
+	switch(cmd) { 
+		case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+		//data[0] = PHY_ADDRESS;
+		case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
 		//data[3] = mdio_read(ioaddr, data[0], data[1]); 
 		return 0;
-
-	case SIOCSMIIREG:		/* Write the specified MII register */
-	case SIOCDEVPRIVATE+2:		/* binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
 		//mdio_write(ioaddr, data[0], data[1], data[2]);
 		return 0;
-
-	default:
+		default:
 		return -EOPNOTSUPP;
 	}
 }
@@ -1389,7 +1897,6 @@
 			/* set Speed to 100Mbps, Half Duplex */
 			/* disable auto negotiation and enable 100MBit Mode */
 			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			printk("read control %x\n", control);
 			control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX);
 			control |= MII_CNTL_F100;
 			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
diff -urN linux-2.4.23-bk1/drivers/net/au1000_eth.h linux-2.4.23-bk2/drivers/net/au1000_eth.h
--- linux-2.4.23-bk1/drivers/net/au1000_eth.h	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/au1000_eth.h	2003-12-03 02:49:52.000000000 -0800
@@ -1,10 +1,13 @@
 /*
- * Alchemy Semi Au1000 ethernet driver include file
+ *
+ * Alchemy Au1x00 ethernet driver include file
  *
  * Author: Pete Popov <ppopov@mvista.com>
  *
  * Copyright 2001 MontaVista Software Inc.
  *
+ * ########################################################################
+ *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
@@ -17,14 +20,16 @@
  *  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 <linux/config.h>
 
 
-#define NUM_INTERFACES 2
 #define MAC_IOSIZE 0x10000
-#define NUM_RX_DMA 4       /* Au1000 has 4 rx hardware descriptors */
-#define NUM_TX_DMA 4       /* Au1000 has 4 tx hardware descriptors */
+#define NUM_RX_DMA 4       /* Au1x00 has 4 rx hardware descriptors */
+#define NUM_TX_DMA 4       /* Au1x00 has 4 tx hardware descriptors */
 
 #define NUM_RX_BUFFS 4
 #define NUM_TX_BUFFS 4
@@ -33,12 +38,6 @@
 #define ETH_TX_TIMEOUT HZ/4
 #define MAC_MIN_PKT_SIZE 64
 
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-#define PHY_ADDRESS              0
-#define PHY_CONTROL_DEFAULT 0x3000
-#define PHY_CONTROL_REG_ADDR     0
-#endif
-
 #define MULTICAST_FILTER_LIMIT 64
 
 /* FIXME 
@@ -54,11 +53,13 @@
 #define MII_ANLPAR  0x0005
 #define MII_AEXP    0x0006
 #define MII_ANEXT   0x0007
-#define MII_LSI_CONFIG 0x0011
-#define MII_LSI_STAT   0x0012
-#define MII_AUX_CNTRL  0x0018
-#define MII_INT        0x001A
+#define MII_LSI_PHY_CONFIG 0x0011
+/* Status register */
+#define MII_LSI_PHY_STAT   0x0012
+#define MII_AMD_PHY_STAT   MII_LSI_PHY_STAT
+#define MII_INTEL_PHY_STAT 0x0011
 
+#define MII_AUX_CNTRL  0x0018
 /* mii registers specific to AMD 79C901 */
 #define	MII_STATUS_SUMMARY = 0x0018
 
@@ -121,23 +122,30 @@
 #define	MII_STSSUM_AUTO  0x0002
 #define MII_STSSUM_SPD   0x0001
 
-/* lsi status register */
-
-#define MII_LSI_STAT_FDX	0x0040
-#define MII_LSI_STAT_SPD	0x0080
+/* lsi phy status register */
+#define MII_LSI_PHY_STAT_FDX	0x0040
+#define MII_LSI_PHY_STAT_SPD	0x0080
+
+/* amd phy status register */
+#define MII_AMD_PHY_STAT_FDX	0x0800
+#define MII_AMD_PHY_STAT_SPD	0x0400
+
+/* intel phy status register */
+#define MII_INTEL_PHY_STAT_FDX	0x0200
+#define MII_INTEL_PHY_STAT_SPD	0x4000
 
 /* Auxilliary Control/Status Register */
 #define MII_AUX_FDX      0x0001
 #define MII_AUX_100      0x0002
 #define MII_AUX_F100     0x0004
 #define MII_AUX_ANEG     0x0008
-#define MII_FDX_LED	 0x8000
 
 typedef struct mii_phy {
 	struct mii_phy * next;
 	struct mii_chip_info * chip_info;
-	int phy_addr;
 	u16 status;
+	u32 *mii_control_reg;
+	u32 *mii_data_reg;
 } mii_phy_t;
 
 struct phy_ops {
@@ -204,6 +212,7 @@
 	u32 tx_tail;
 	u32 tx_full;
 
+	int mac_id;
 	mii_phy_t *mii;
 	struct phy_ops *phy_ops;
 	
@@ -217,7 +226,7 @@
 	u8 *hash_table;
 	u32 hash_mode;
 	u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
-	u32 phy_addr;          /* PHY address */
+	int phy_addr;          /* phy address */
 	u32 options;           /* User-settable misc. driver options. */
 	u32 drv_flags;
 	struct net_device_stats stats;
diff -urN linux-2.4.23-bk1/drivers/net/declance.c linux-2.4.23-bk2/drivers/net/declance.c
--- linux-2.4.23-bk1/drivers/net/declance.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.23-bk2/drivers/net/declance.c	2003-12-03 02:49:52.000000000 -0800
@@ -5,7 +5,7 @@
  *
  *      adopted from sunlance.c by Richard van den Berg
  *
- *      Copyright (C) 2002  Maciej W. Rozycki
+ *      Copyright (C) 2002, 2003  Maciej W. Rozycki
  *
  *      additional sources:
  *      - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -52,6 +52,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/spinlock.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
 
@@ -271,7 +272,7 @@
 			lp->tx_old - lp->tx_new-1)
 
 /* The lance control ports are at an absolute address, machine and tc-slot
- * dependant.
+ * dependent.
  * DECstations do only 32-bit access and the LANCE uses 16 bit addresses,
  * so we have to give the structure an extra member making rap pointing
  * at the right address
@@ -783,19 +784,29 @@
 
 	/* Associate IRQ with lance_interrupt */
 	if (request_irq(dev->irq, &lance_interrupt, 0, "lance", dev)) {
-		printk("lance: Can't get IRQ %d\n", dev->irq);
+		printk("%s: Can't get IRQ %d\n", dev->name, dev->irq);
 		return -EAGAIN;
 	}
 	if (lp->dma_irq >= 0) {
+		unsigned long flags;
+
 		if (request_irq(lp->dma_irq, &lance_dma_merr_int, 0,
 				"lance error", dev)) {
 			free_irq(dev->irq, dev);
-			printk("lance: Can't get DMA IRQ %d\n", lp->dma_irq);
+			printk("%s: Can't get DMA IRQ %d\n", dev->name,
+				lp->dma_irq);
 			return -EAGAIN;
 		}
+
+		spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+		fast_mb();
 		/* Enable I/O ASIC LANCE DMA.  */
-		fast_wmb();
-		ioasic_write(SSR, ioasic_read(SSR) | LANCE_DMA_EN);
+		ioasic_write(IO_REG_SSR,
+			     ioasic_read(IO_REG_SSR) | IO_SSR_LANCE_DMA_EN);
+
+		fast_mb();
+		spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
 	}
 
 	status = init_restart_lance(lp);
@@ -821,9 +832,18 @@
 	writereg(&ll->rdp, LE_C0_STOP);
 
 	if (lp->dma_irq >= 0) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+		fast_mb();
 		/* Disable I/O ASIC LANCE DMA.  */
-		ioasic_write(SSR, ioasic_read(SSR) & ~LANCE_DMA_EN);
+		ioasic_write(IO_REG_SSR,
+			     ioasic_read(IO_REG_SSR) & ~IO_SSR_LANCE_DMA_EN);
+
 		fast_iob();
+		spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
+
 		free_irq(lp->dma_irq, dev);
 	}
 	free_irq(dev->irq, dev);
@@ -856,8 +876,8 @@
 	volatile struct lance_regs *ll = lp->ll;
 
 	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
-			       dev->name, ll->rdp);
-			lance_reset(dev);
+		dev->name, ll->rdp);
+	lance_reset(dev);
 	netif_wake_queue(dev);
 }
 
@@ -872,10 +892,9 @@
 
 	len = skblen;
 	
-	if(len < ETH_ZLEN)
-	{
+	if (len < ETH_ZLEN) {
 		skb = skb_padto(skb, ETH_ZLEN);
-		if(skb == NULL)
+		if (skb == NULL)
 			return 0;
 		len = ETH_ZLEN;
 	}
@@ -890,7 +909,7 @@
 		  skblen);
 
 	/* Clear the slack of the packet, do I need this? */
-	/* For a firewall its a good idea - AC */
+	/* For a firewall it's a good idea - AC */
 /*
    if (len != skblen)
    memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1);
@@ -927,7 +946,7 @@
 	volatile u16 *mcast_table = (u16 *) & ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 crc;
 
 	/* set all multicast bits */
@@ -1005,6 +1024,8 @@
 static int __init dec_lance_init(const int type, const int slot)
 {
 	static unsigned version_printed;
+	static const char fmt[] = "declance%d";
+	char name[10];
 	struct net_device *dev;
 	struct lance_private *lp;
 	volatile struct lance_regs *ll;
@@ -1019,13 +1040,26 @@
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
 
-	dev = init_etherdev(NULL, sizeof(struct lance_private));
-	if (!dev)
-		return -ENOMEM;
+	i = 0;
+	dev = root_lance_dev;
+	while (dev) {
+		i++;
+		lp = (struct lance_private *)dev->priv;
+		dev = lp->next;
+	}
+	snprintf(name, sizeof(name), fmt, i);
+
+	dev = alloc_etherdev(sizeof(struct lance_private));
+	if (!dev) {
+		printk(KERN_ERR "%s: Unable to allocate etherdev, aborting.\n",
+			name);
+		ret = -ENOMEM;
+		goto err_out;
+	}
 	SET_MODULE_OWNER(dev);
 
 	/*
-	 * init_etherdev ensures the data structures used by the LANCE
+	 * alloc_etherdev ensures the data structures used by the LANCE
 	 * are aligned.
 	 */
 	lp = (struct lance_private *) dev->priv;
@@ -1036,7 +1070,7 @@
 	switch (type) {
 #ifdef CONFIG_TC
 	case ASIC_LANCE:
-		dev->base_addr = system_base + LANCE;
+		dev->base_addr = system_base + IOASIC_LANCE;
 
 		/* buffer space for the on-board LANCE shared memory */
 		/*
@@ -1045,7 +1079,7 @@
 		dev->mem_start = KSEG1ADDR(0x00020000);
 		dev->mem_end = dev->mem_start + 0x00020000;
 		dev->irq = dec_interrupt[DEC_IRQ_LANCE];
-		esar_base = system_base + ESAR;
+		esar_base = system_base + IOASIC_ESAR;
 
 		/* Workaround crash with booting KN04 2.1k from Disk */
 		memset((void *)dev->mem_start, 0,
@@ -1074,7 +1108,8 @@
 
 		/* Setup I/O ASIC LANCE DMA.  */
 		lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR];
-		ioasic_write(LANCE_DMA_P, PHYSADDR(dev->mem_start) << 3);
+		ioasic_write(IO_REG_LANCE_DMA_P,
+			     PHYSADDR(dev->mem_start) << 3);
 
 		break;
 
@@ -1139,9 +1174,10 @@
 		break;
 
 	default:
-		printk("declance_init called with unknown type\n");
+		printk(KERN_ERR "%s: declance_init called with unknown type\n",
+			name);
 		ret = -ENODEV;
-		goto err_out;
+		goto err_out_free_dev;
 	}
 
 	ll = (struct lance_regs *) dev->base_addr;
@@ -1151,19 +1187,21 @@
 	/* First, check for test pattern */
 	if (esar[0x60] != 0xff && esar[0x64] != 0x00 &&
 	    esar[0x68] != 0x55 && esar[0x6c] != 0xaa) {
-		printk("Ethernet station address prom not found!\n");
+		printk(KERN_ERR
+			"%s: Ethernet station address prom not found!\n",
+			name);
 		ret = -ENODEV;
-		goto err_out;
+		goto err_out_free_dev;
 	}
 	/* Check the prom contents */
 	for (i = 0; i < 8; i++) {
 		if (esar[i * 4] != esar[0x3c - i * 4] &&
 		    esar[i * 4] != esar[0x40 + i * 4] &&
 		    esar[0x3c - i * 4] != esar[0x40 + i * 4]) {
-			printk("Something is wrong with the ethernet "
-			       "station address prom!\n");
+			printk(KERN_ERR "%s: Something is wrong with the "
+				"ethernet station address prom!\n", name);
 			ret = -ENODEV;
-			goto err_out;
+			goto err_out_free_dev;
 		}
 	}
 
@@ -1176,13 +1214,13 @@
 	 */
 	switch (type) {
 	case ASIC_LANCE:
-		printk("%s: IOASIC onboard LANCE, addr = ", dev->name);
+		printk("%s: IOASIC onboard LANCE, addr = ", name);
 		break;
 	case PMAD_LANCE:
-		printk("%s: PMAD-AA, addr = ", dev->name);
+		printk("%s: PMAD-AA, addr = ", name);
 		break;
 	case PMAX_LANCE:
-		printk("%s: PMAX onboard LANCE, addr = ", dev->name);
+		printk("%s: PMAX onboard LANCE, addr = ", name);
 		break;
 	}
 	for (i = 0; i < 6; i++) {
@@ -1219,11 +1257,20 @@
 	lp->multicast_timer.data = (unsigned long) dev;
 	lp->multicast_timer.function = &lance_set_multicast_retry;
 
+	ret = register_netdev(dev);
+	if (ret) {
+		printk(KERN_ERR
+			"%s: Unable to register netdev, aborting.\n", name);
+		goto err_out_free_dev;
+	}
+
+	printk("%s: registered as %s.\n", name, dev->name);
 	return 0;
 
-err_out:
-	unregister_netdev(dev);
+err_out_free_dev:
 	kfree(dev);
+
+err_out:
 	return ret;
 }
 
diff -urN linux-2.4.23-bk1/drivers/net/gt64240eth.c linux-2.4.23-bk2/drivers/net/gt64240eth.c
--- linux-2.4.23-bk1/drivers/net/gt64240eth.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/gt64240eth.c	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,1854 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Patton Electronics Company
+ * Copyright (C) 2002 Momentum Computer
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or support@mvista.com
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
+ * 
+ * Modified for the Gallileo/Marvell GT-64240 Communication Controller.
+ *
+ * Support for Rx NAPI, Rx checksum offload, IOCTL and ETHTOOL added
+ * Manish Lachwani (lachwani@pmc-sierra.com) - 09/16/2003
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/mii.h>
+
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define DESC_DATA_BE 1
+
+#include "gt64240eth.h"
+
+// enable this port (set hash size to 1/2K)
+//- #define PORT_CONFIG pcrHS
+#define PORT_CONFIG (pcrHS | pcrHD)
+//- #define PORT_CONFIG pcrHS |pcrPM |pcrPBF|pcrHDM
+//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS);
+//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM);
+//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM | 1<<pcrLPBKBit);
+
+// clear all the MIB ctr regs
+#define EXT_CONFIG_CLEAR (pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen | pcxrPRIOrxOverride | pcxrRMIIen)
+
+/*
+ * _debug level:
+ * <= 2	none.
+ *  > 2	some warnings such as queue full, .....
+ *  > 3	lots of change-of-state messages.
+ *  > 4	EXTENSIVE data/descriptor dumps.
+ */
+#ifdef GT64240_DEBUG
+static int gt64240_debug = GT64240_DEBUG;
+#else
+static int gt64240_debug = 0;
+#endif
+
+/********************************************************/
+
+// prototypes
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle);
+static void dmafree(size_t size, void *vaddr);
+static void gt64240_delay(int msec);
+static int gt64240_add_hash_entry(struct net_device *dev,
+				  unsigned char *addr);
+static void read_mib_counters(struct gt64240_private *gp);
+static int read_MII(struct net_device *dev, u32 reg);
+static int write_MII(struct net_device *dev, u32 reg, u16 data);
+#if 1
+static void dump_tx_ring(struct net_device *dev);
+static void dump_rx_ring(struct net_device *dev);
+#endif
+static void dump_MII(struct net_device *dev);
+static void dump_tx_desc(struct net_device *dev, int i);
+static void dump_rx_desc(struct net_device *dev, int i);
+static void dump_skb(struct net_device *dev, struct sk_buff *skb);
+static void dump_hw_addr(unsigned char *addr_str);
+static void update_stats(struct gt64240_private *gp);
+static void abort(struct net_device *dev, u32 abort_bits);
+static void hard_stop(struct net_device *dev);
+static void enable_ether_irq(struct net_device *dev);
+static void disable_ether_irq(struct net_device *dev);
+static int __init gt64240_probe1(uint32_t ioaddr, int irq, int port_num);
+static void reset_tx(struct net_device *dev);
+static void reset_rx(struct net_device *dev);
+static int gt64240_init(struct net_device *dev);
+static int gt64240_open(struct net_device *dev);
+static int gt64240_close(struct net_device *dev);
+static int gt64240_tx(struct sk_buff *skb, struct net_device *dev);
+#ifdef GT64240_NAPI
+static int gt64240_poll(struct net_device *dev, int *budget);
+static int gt64240_rx(struct net_device *dev, u32 status, int budget);
+#else
+static int gt64240_rx(struct net_device *dev, u32 status);
+#endif
+static void gt64240_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void gt64240_tx_timeout(struct net_device *dev);
+static void gt64240_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *gt64240_get_stats(struct net_device *dev);
+
+extern char *__init prom_getcmdline(void);
+extern int prom_get_mac_addrs(unsigned char
+			      station_addr[NUM_INTERFACES][6]);
+
+static char version[] __devinitdata =
+	"gt64240eth.o: version 0.1, <www.patton.com>\n";
+
+// PHY device addresses
+static u32 gt64240_phy_addr[NUM_INTERFACES] __devinitdata = { 0x8, 0x1, 0xa };
+
+// Need real Ethernet addresses -- in parse_mac_addr_options(),
+// these will be replaced by prom_get_mac_addrs() and/or prom_getcmdline().
+static unsigned char gt64240_station_addr[NUM_INTERFACES][6] = {
+	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
+	{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+	{0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
+};
+
+static int max_interrupt_work = 32;
+
+/*
+ * Base address and interupt of the GT64240 ethernet controllers
+ */
+static struct {
+	unsigned int port;
+	int irq;
+} gt64240_iflist[NUM_INTERFACES] = {
+	{
+	GT64240_ETH0_BASE, 8}, {
+	GT64240_ETH1_BASE, 8}, {
+	GT64240_ETH2_BASE, 8}
+};
+
+/*
+  DMA memory allocation, derived from pci_alloc_consistent.
+*/
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle)
+{
+	void *ret;
+
+	ret =
+	    (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA,
+				      get_order(size));
+
+	if (ret != NULL) {
+		dma_cache_inv((unsigned long) ret, size);
+		if (dma_handle != NULL)
+			*dma_handle = virt_to_phys(ret);
+
+		/* bump virtual address up to non-cached area */
+		ret = (void *) KSEG1ADDR(ret);
+	}
+
+	return ret;
+}
+
+static void dmafree(size_t size, void *vaddr)
+{
+	vaddr = (void *) KSEG0ADDR(vaddr);
+	free_pages((unsigned long) vaddr, get_order(size));
+}
+
+static void gt64240_delay(int ms)
+{
+	if (in_interrupt())
+		return;
+	else {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(ms * HZ / 1000);
+	}
+}
+
+unsigned char prom_mac_addr_base[6];
+
+int prom_get_mac_addrs(unsigned char station_addr[NUM_INTERFACES][6])
+{
+	memcpy(station_addr[0], prom_mac_addr_base, 6);
+	memcpy(station_addr[1], prom_mac_addr_base, 6);
+	memcpy(station_addr[2], prom_mac_addr_base, 6);
+
+	station_addr[1][5] += 1;
+	station_addr[2][5] += 2;
+
+	return 0;
+}
+
+void parse_mac_addr_options(void)
+{
+	prom_get_mac_addrs(gt64240_station_addr);
+}
+
+static int read_MII(struct net_device *dev, u32 reg)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int timedout = 20;
+	u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) |
+	    (reg << smirRegAdBit);
+
+	// wait for last operation to complete
+	while ((GT64240_READ(GT64240_ETH_SMI_REG)) & smirBusy) {
+		// snooze for 1 msec and check again
+		gt64240_delay(1);
+
+		if (--timedout == 0) {
+			printk("%s: read_MII busy timeout!!\n", dev->name);
+			return -1;
+		}
+	}
+
+	GT64240_WRITE(GT64240_ETH_SMI_REG, smir);
+
+	timedout = 20;
+	// wait for read to complete
+	while (!
+	       ((smir =
+		 GT64240_READ(GT64240_ETH_SMI_REG)) & smirReadValid)) {
+		// snooze for 1 msec and check again
+		gt64240_delay(1);
+
+		if (--timedout == 0) {
+			printk("%s: read_MII timeout!!\n", dev->name);
+			return -1;
+		}
+	}
+
+	return (int) (smir & smirDataMask);
+}
+
+/* Ethtool support */
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+		/* Get driver info */
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, "gt64260",
+				sizeof(info.driver) - 1);
+			strncpy(info.version, version,
+				sizeof(info.version) - 1);
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+		/* get settings */
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			spin_lock_irq(&gp->lock);
+			mii_ethtool_gset(&gp->mii_if, &ecmd);
+			spin_unlock_irq(&gp->lock);
+			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set settings */
+	case ETHTOOL_SSET:{
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+				return -EFAULT;
+			spin_lock_irq(&gp->lock);
+			r = mii_ethtool_sset(&gp->mii_if, &ecmd);
+			spin_unlock_irq(&gp->lock);
+			return r;
+		}
+		/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST:{
+			return mii_nway_restart(&gp->mii_if);
+		}
+		/* get link status */
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = mii_link_ok(&gp->mii_if);
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+		/* get message-level */
+	case ETHTOOL_GMSGLVL:{
+			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+			edata.data = 0;	/* XXX */
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set message-level */
+	case ETHTOOL_SMSGLVL:{
+			struct ethtool_value edata;
+			if (copy_from_user
+			    (&edata, useraddr, sizeof(edata)))
+				return -EFAULT;
+			/* debug = edata.data; *//* XXX */
+			return 0;
+		}
+	}
+	return -EOPNOTSUPP;
+}
+
+static int gt64240_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct mii_ioctl_data *data =
+	    (struct mii_ioctl_data *) &rq->ifr_data;
+	int phy = dev->base_addr & 0x1f;
+	int retval;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		retval = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCDEVPRIVATE:	/* for binary compat, remove in 2.5 */
+		data->phy_id = phy;
+		/* Fall through */
+
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCDEVPRIVATE + 1:	/* for binary compat, remove in 2.5 */
+		data->val_out = read_MII(dev, data->reg_num & 0x1f);
+		retval = 0;
+		break;
+
+	case SIOCSMIIREG:	/* Write MII PHY register. */
+	case SIOCDEVPRIVATE + 2:	/* for binary compat, remove in 2.5 */
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+		} else {
+			write_MII(dev, data->reg_num & 0x1f, data->val_in);
+			retval = 0;
+		}
+		break;
+
+	default:
+		retval = -EOPNOTSUPP;
+		break;
+	}
+	return retval;
+}
+
+static void dump_tx_desc(struct net_device *dev, int i)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	gt64240_td_t *td = &gp->tx_ring[i];
+
+	printk
+	    ("%s:tx[%d]: self=%08x cmd=%08x, cnt=%4d. bufp=%08x, next=%08x\n",
+	     dev->name, i, td, td->cmdstat, td->byte_cnt, td->buff_ptr,
+	     td->next);
+}
+
+static void dump_rx_desc(struct net_device *dev, int i)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	gt64240_rd_t *rd = &gp->rx_ring[i];
+
+	printk
+	    ("%s:rx_dsc[%d]: self=%08x cst=%08x,size=%4d. cnt=%4d. bufp=%08x, next=%08x\n",
+	     dev->name, i, rd, rd->cmdstat, rd->buff_sz, rd->byte_cnt,
+	     rd->buff_ptr, rd->next);
+}
+
+// These routines work, just disabled to avoid compile warnings
+static int write_MII(struct net_device *dev, u32 reg, u16 data)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int timedout = 20;
+	u32 smir =
+	    (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data;
+
+	// wait for last operation to complete
+	while (GT64240_READ(GT64240_ETH_SMI_REG) & smirBusy) {
+		// snooze for 1 msec and check again
+		gt64240_delay(1);
+
+		if (--timedout == 0) {
+			printk("%s: write_MII busy timeout!!\n",
+			       dev->name);
+			return -1;
+		}
+	}
+
+	GT64240_WRITE(GT64240_ETH_SMI_REG, smir);
+	return 0;
+}
+
+static void dump_tx_ring(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int i;
+
+	printk("%s: dump_tx_ring: txno/txni/cnt=%d/%d/%d\n",
+	       dev->name, gp->tx_next_out, gp->tx_next_in, gp->tx_count);
+
+	for (i = 0; i < TX_RING_SIZE; i++)
+		dump_tx_desc(dev, i);
+}
+
+static void dump_rx_ring(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int i;
+
+	printk("%s: dump_rx_ring: rxno=%d\n", dev->name, gp->rx_next_out);
+
+	for (i = 0; i < RX_RING_SIZE; i++)
+		dump_rx_desc(dev, i);
+}
+
+static void dump_MII(struct net_device *dev)
+{
+	int i, val;
+
+	for (i = 0; i < 7; i++) {
+		if ((val = read_MII(dev, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+	for (i = 16; i < 21; i++) {
+		if ((val = read_MII(dev, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+}
+
+
+static void dump_hw_addr(unsigned char *addr_str)
+{
+	int i;
+	for (i = 0; i < 6; i++) {
+		printk("%2.2x", addr_str[i]);
+		printk(i < 5 ? ":" : "\n");
+	}
+}
+
+
+static void dump_skb(struct net_device *dev, struct sk_buff *skb)
+{
+	int i;
+	unsigned char *skbdata;
+
+	printk("%s: dump_skb: skb=%p, skb->data=%p, skb->len=%d.",
+	       dev->name, skb, skb->data, skb->len);
+
+	skbdata = (unsigned char *) KSEG1ADDR(skb->data);
+
+	for (i = 0; i < skb->len; i++) {
+		if (!(i % 16))
+			printk("\r\n   %3.3x: %2.2x,", i, skbdata[i]);
+		else
+			printk("%2.2x,", skbdata[i]);
+	}
+	printk("\r\n");
+}
+
+
+static void dump_data(struct net_device *dev, char *ptr, int len)
+{
+	int i;
+	unsigned char *data;
+
+	printk("%s: dump_data: ptr=%p, len=%d.", dev->name, ptr, len);
+
+	data = (unsigned char *) KSEG1ADDR(ptr);
+
+	for (i = 0; i < len; i++) {
+		if (!(i % 16))
+			printk("\n   %3.3x: %2.2x,", i, data[i]);
+		else
+			printk("%2.2x,", data[i]);
+	}
+	printk("\n");
+}
+
+
+/*--------------------------------------------------------------*/
+/*	A D D    H A S H    E N T R Y				*/
+/*--------------------------------------------------------------*/
+static int gt64240_add_hash_entry(struct net_device *dev,
+				  unsigned char *addr)
+{
+	struct gt64240_private *gp;
+	int i;
+	u32 value1, value0, *entry;
+	u16 hashResult;
+	unsigned char hash_ea[6];
+	static int flag = 0;
+	static unsigned char swapped[256];
+
+	if (flag == 0) {	/* Create table to swap bits in a byte  */
+		flag = 1;
+		for (i = 0; i < 256; i++) {
+			swapped[i] = (i & 0x01) << 7;
+			swapped[i] |= (i & 0x02) << 5;
+			swapped[i] |= (i & 0x04) << 3;
+			swapped[i] |= (i & 0x08) << 1;
+			swapped[i] |= (i & 0x10) >> 1;
+			swapped[i] |= (i & 0x20) >> 3;
+			swapped[i] |= (i & 0x40) >> 5;
+			swapped[i] |= (i & 0x80) >> 7;
+		}
+	}
+
+	for (i = 0; i < 6; i++) {	/* swap bits from mac to create hash mac */
+		hash_ea[i] = swapped[addr[i]];
+	}
+
+	gp = (struct gt64240_private *) dev->priv;
+
+	/* create hash entry address    */
+	hashResult = (((hash_ea[5] >> 2) & 0x3F) << 9) & 0x7E00;
+	hashResult |= ((hash_ea[4] & 0x7F) << 2) | (hash_ea[5] & 0x03);
+	hashResult ^=
+	    ((hash_ea[3] & 0xFF) << 1) | ((hash_ea[4] >> 7) & 0x01);
+	hashResult ^= ((hash_ea[1] & 0x01) << 8) | (hash_ea[2] & 0xFF);
+
+	value0 = hteValid | hteRD;	/* Create hash table entry value */
+	value0 |= (u32) addr[0] << 3;
+	value0 |= (u32) addr[1] << 11;
+	value0 |= (u32) addr[2] << 19;
+	value0 |= ((u32) addr[3] & 0x1f) << 27;
+
+	value1 = ((u32) addr[3] >> 5) & 0x07;
+	value1 |= (u32) addr[4] << 3;
+	value1 |= (u32) addr[5] << 11;
+
+	/* Inset entry value into hash table */
+	for (i = 0; i < HASH_HOP_NUMBER; i++) {
+		entry = (u32 *) ((u32) gp->hash_table +
+				 (((u32) hashResult & 0x07ff) << 3));
+		if ((*entry & hteValid) && !(*entry & hteSkip)) {
+			hashResult += 2;	/* oops, occupied, go to next entry */
+		} else {
+#ifdef __LITTLE_ENDIAN
+			entry[1] = value1;
+			entry[0] = value0;
+#else
+			entry[0] = value1;
+			entry[1] = value0;
+#endif
+			break;
+		}
+	}
+	if (i >= HASH_HOP_NUMBER) {
+		printk("%s: gt64240_add_hash_entry expired!\n", dev->name);
+		return (-1);
+	}
+	return (0);
+}
+
+
+static void read_mib_counters(struct gt64240_private *gp)
+{
+	u32 *mib_regs = (u32 *) & gp->mib;
+	int i;
+
+	for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++)
+		mib_regs[i] =
+		    GT64240ETH_READ(gp,
+				    GT64240_ETH_MIB_COUNT_BASE +
+				    i * sizeof(u32));
+}
+
+
+static void update_stats(struct gt64240_private *gp)
+{
+	mib_counters_t *mib = &gp->mib;
+	struct net_device_stats *stats = &gp->stats;
+
+	read_mib_counters(gp);
+
+	stats->rx_packets = mib->totalFramesReceived;
+	stats->tx_packets = mib->framesSent;
+	stats->rx_bytes = mib->totalByteReceived;
+	stats->tx_bytes = mib->byteSent;
+	stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
+	//the tx error counters are incremented by the ISR
+	//rx_dropped incremented by gt64240_rx
+	//tx_dropped incremented by gt64240_tx
+	stats->multicast = mib->multicastFramesReceived;
+	// collisions incremented by gt64240_tx_complete
+	stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
+	// The RxError condition means the Rx DMA encountered a
+	// CPU owned descriptor, which, if things are working as
+	// they should, means the Rx ring has overflowed.
+	stats->rx_over_errors = mib->macRxError;
+	stats->rx_crc_errors = mib->cRCError;
+}
+
+static void abort(struct net_device *dev, u32 abort_bits)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int timedout = 100;	// wait up to 100 msec for hard stop to complete
+
+	if (gt64240_debug > 3)
+		printk("%s: abort\n", dev->name);
+
+	// Return if neither Rx or Tx abort bits are set
+	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
+		return;
+
+	// make sure only the Rx/Tx abort bits are set
+	abort_bits &= (sdcmrAR | sdcmrAT);
+
+	spin_lock(&gp->lock);
+
+	// abort any Rx/Tx DMA immediately
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, abort_bits);
+
+	if (gt64240_debug > 3)
+		printk("%s: abort: SDMA cmd  = %x/%x\n",
+		       dev->name, abort_bits, GT64240ETH_READ(gp,
+							      GT64240_ETH_SDMA_COMM));
+
+	// wait for abort to complete
+	while ((GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM)) & abort_bits) {
+		// snooze for 20 msec and check again
+		gt64240_delay(1);
+
+		if (--timedout == 0) {
+			printk("%s: abort timeout!!\n", dev->name);
+			break;
+		}
+	}
+
+	spin_unlock(&gp->lock);
+}
+
+
+static void hard_stop(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+
+	if (gt64240_debug > 3)
+		printk("%s: hard stop\n", dev->name);
+
+	disable_ether_irq(dev);
+
+	abort(dev, sdcmrAR | sdcmrAT);
+
+	// disable port
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, 0);
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_hard_stop: Port Config=%x\n",
+		       dev->name, GT64240ETH_READ(gp,
+						  GT64240_ETH_PORT_CONFIG));
+
+}
+
+
+static void enable_ether_irq(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	u32 intMask;
+
+	intMask =
+	    icrTxBufferLow | icrTxEndLow | icrTxErrorLow |
+	    icrTxBufferHigh | icrTxEndHigh | icrTxErrorHigh | icrTxUdr |
+	    icrRxBuffer | icrRxOVR | icrRxError | icrMIIPhySTC |
+	    icrEtherIntSum;
+
+
+//- GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); /* CLEAR existing ints */
+	// unmask device interrupts:
+	GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, intMask);
+
+	// now route ethernet interrupts to GT PCI1 (eth0 and eth1 will be
+	// sharing it).
+	GT_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, &intMask);
+	intMask |= 1 << gp->port_num;
+	GT_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask);
+}
+
+static void disable_ether_irq(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	u32 intMask;
+
+	GT_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, &intMask);
+	intMask &= ~(1 << gp->port_num);
+	GT_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask);
+
+	// mask all device interrupts: 
+	GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, 0);
+}
+
+#ifdef GT64240_NAPI
+static inline void __netif_rx_complete(struct net_device *dev)
+{
+	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+		BUG();
+	list_del(&dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+#endif
+
+
+/*
+ * Probe for a GT64240 ethernet controller.
+ */
+static int __init gt64240_probe(void)
+{
+	unsigned int base_addr = 0;
+	int i;
+	int found = 0;
+
+	if (gt64240_debug > 2)
+		printk("gt64240_probe at 0x%08x\n", base_addr);
+
+	parse_mac_addr_options();
+
+	for (i = 0; i < NUM_INTERFACES; i++) {
+		int base_addr = gt64240_iflist[i].port;
+
+		if (check_region(base_addr, GT64240_ETH_IO_SIZE)) {
+			printk("gt64240_probe: ioaddr 0x%lx taken?\n",
+			       base_addr);
+			continue;
+		}
+
+		if (gt64240_probe1(base_addr, gt64240_iflist[i].irq, i) ==
+		    0) {
+			/* Does not seem to be the "traditional" way folks do this, */
+			/* but I want to init both eth ports if at all possible!    */
+			/* So, until I find out the "correct" way to do this:       */
+			if (++found == NUM_INTERFACES)	/* That's all of them! */
+				return 0;
+		}
+	}
+	if (found)
+		return 0;	/* as long as we found at least one! */
+	return -ENODEV;
+}
+
+module_init(gt64240_probe);
+
+static int __init gt64240_probe1(uint32_t ioaddr, int irq, int port_num)
+{
+	struct net_device *dev = NULL;
+	static unsigned version_printed = 0;
+	struct gt64240_private *gp = NULL;
+	int retval;
+	u16 vendor_id, device_id;
+	u32 cpuConfig;
+	unsigned char chip_rev;
+
+	// probe for GT64240 by reading PCI0 vendor/device ID register
+	pcibios_read_config_word(0, 0, PCI_VENDOR_ID, &vendor_id);
+	pcibios_read_config_word(0, 0, PCI_DEVICE_ID, &device_id);
+
+	dev = init_etherdev(NULL, sizeof(struct gt64240_private));
+
+	if (gt64240_debug > 2)
+		printk
+		    ("%s: gt64240_probe1 vendId=0x%08x, devId=0x%08x, addr=0x%08lx, irq=%d.,port=%d.\n",
+		     dev->name, vendor_id, device_id, ioaddr, irq,
+		     port_num);
+
+	if (irq < 0) {
+		printk
+		    ("gt64240_probe1: irq unknown - probing not supported\n");
+		return -ENODEV;
+	}
+#if 1				/* KLUDGE Alert: no check on return value: */
+	if (!request_region(ioaddr, GT64240_ETH_IO_SIZE, "gt64240eth"))
+		printk("*** request_region() failed!\n");
+#endif
+
+	cpuConfig = GT64240_READ(CPU_CONFIGURATION);
+	printk("gt64240_probe1: cpu in %s-endian mode\n",
+	       (cpuConfig & (1 << 12)) ? "little" : "big");
+
+	printk
+	    ("%s: GT64240 found at ioaddr 0x%lx, irq %d., PCI devID=%x\n",
+	     dev->name, ioaddr, irq, device_id);
+
+	/* Allocate a new 'dev' if needed. */
+	if (dev == NULL)
+		dev = init_etherdev(0, sizeof(struct gt64240_private));
+
+	if (gt64240_debug && version_printed++ == 0)
+		printk("%s: %s", dev->name, version);
+
+	/* private struct aligned and zeroed by init_etherdev */
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	memcpy(dev->dev_addr, gt64240_station_addr[port_num],
+	       sizeof(dev->dev_addr));
+
+	printk("%s: HW Address ", dev->name);
+	dump_hw_addr(dev->dev_addr);
+
+	/* Initialize our private structure. */
+	if (dev->priv == NULL) {
+
+		gp = (struct gt64240_private *) kmalloc(sizeof(*gp),
+							GFP_KERNEL);
+		if (gp == NULL) {
+			retval = -ENOMEM;
+			goto free_region;
+		}
+
+		dev->priv = gp;
+	}
+
+	gp = dev->priv;
+
+	memset(gp, 0, sizeof(*gp));	// clear it
+
+	gp->port_num = port_num;
+	gp->io_size = GT64240_ETH_IO_SIZE;
+	gp->port_offset = port_num * GT64240_ETH_IO_SIZE;
+	gp->phy_addr = gt64240_phy_addr[port_num];
+
+	pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev);
+	gp->chip_rev = chip_rev;
+	printk("%s: GT64240 chip revision=%d\n", dev->name, gp->chip_rev);
+
+	printk("%s: GT64240 ethernet port %d\n", dev->name, gp->port_num);
+
+#ifdef GT64240_NAPI
+	printk("Rx NAPI supported \n");
+#endif
+
+/* MII Initialization */
+	gp->mii_if.dev = dev;
+	gp->mii_if.phy_id = dev->base_addr;
+	gp->mii_if.mdio_read = read_MII;
+	gp->mii_if.mdio_write = write_MII;
+	gp->mii_if.advertising = read_MII(dev, MII_ADVERTISE);
+
+	// Allocate Rx and Tx descriptor rings
+	if (gp->rx_ring == NULL) {
+		// All descriptors in ring must be 16-byte aligned
+		gp->rx_ring = dmaalloc(sizeof(gt64240_rd_t) * RX_RING_SIZE
+				       +
+				       sizeof(gt64240_td_t) * TX_RING_SIZE,
+				       &gp->rx_ring_dma);
+		if (gp->rx_ring == NULL) {
+			retval = -ENOMEM;
+			goto free_region;
+		}
+
+		gp->tx_ring =
+		    (gt64240_td_t *) (gp->rx_ring + RX_RING_SIZE);
+		gp->tx_ring_dma =
+		    gp->rx_ring_dma + sizeof(gt64240_rd_t) * RX_RING_SIZE;
+	}
+	// Allocate the Rx Data Buffers
+	if (gp->rx_buff == NULL) {
+		gp->rx_buff =
+		    dmaalloc(PKT_BUF_SZ * RX_RING_SIZE, &gp->rx_buff_dma);
+		if (gp->rx_buff == NULL) {
+			dmafree(sizeof(gt64240_rd_t) * RX_RING_SIZE
+				+ sizeof(gt64240_td_t) * TX_RING_SIZE,
+				gp->rx_ring);
+			retval = -ENOMEM;
+			goto free_region;
+		}
+	}
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_probe1, rx_ring=%p, tx_ring=%p\n",
+		       dev->name, gp->rx_ring, gp->tx_ring);
+
+	// Allocate Rx Hash Table
+	if (gp->hash_table == NULL) {
+		gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE,
+						   &gp->hash_table_dma);
+		if (gp->hash_table == NULL) {
+			dmafree(sizeof(gt64240_rd_t) * RX_RING_SIZE
+				+ sizeof(gt64240_td_t) * TX_RING_SIZE,
+				gp->rx_ring);
+			dmafree(PKT_BUF_SZ * RX_RING_SIZE, gp->rx_buff);
+			retval = -ENOMEM;
+			goto free_region;
+		}
+	}
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_probe1, hash=%p\n",
+		       dev->name, gp->hash_table);
+
+	spin_lock_init(&gp->lock);
+
+	dev->open = gt64240_open;
+	dev->hard_start_xmit = gt64240_tx;
+	dev->stop = gt64240_close;
+	dev->get_stats = gt64240_get_stats;
+	dev->do_ioctl = gt64240_ioctl;
+	dev->set_multicast_list = gt64240_set_rx_mode;
+	dev->tx_timeout = gt64240_tx_timeout;
+	dev->watchdog_timeo = GT64240ETH_TX_TIMEOUT;
+
+#ifdef GT64240_NAPI
+	dev->poll = gt64240_poll;
+	dev->weight = 64;
+#endif
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
+
+      free_region:
+	release_region(ioaddr, gp->io_size);
+	unregister_netdev(dev);
+	if (dev->priv != NULL)
+		kfree(dev->priv);
+	kfree(dev);
+	printk("%s: gt64240_probe1 failed.  Returns %d\n",
+	       dev->name, retval);
+	return retval;
+}
+
+
+static void reset_tx(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int i;
+
+	abort(dev, sdcmrAT);
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (gp->tx_skbuff[i]) {
+			if (in_interrupt())
+				dev_kfree_skb_irq(gp->tx_skbuff[i]);
+			else
+				dev_kfree_skb(gp->tx_skbuff[i]);
+			gp->tx_skbuff[i] = NULL;
+		}
+//-     gp->tx_ring[i].cmdstat = 0; // CPU owns
+		gp->tx_ring[i].cmdstat =
+		    (u32) (txGenCRC | txEI | txPad | txFirst | txLast);
+		gp->tx_ring[i].byte_cnt = 0;
+		gp->tx_ring[i].buff_ptr = 0;
+		gp->tx_ring[i].next =
+		    gp->tx_ring_dma + sizeof(gt64240_td_t) * (i + 1);
+		if (gt64240_debug > 4)
+			dump_tx_desc(dev, i);
+	}
+	/* Wrap the ring. */
+	gp->tx_ring[i - 1].next = gp->tx_ring_dma;
+	if (gt64240_debug > 4)
+		dump_tx_desc(dev, i - 1);
+
+	// setup only the lowest priority TxCDP reg
+	GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,
+			 gp->tx_ring_dma);
+//- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0, 0);     /* ROLLINS */
+//- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,virt_to_phys(&gp->tx_ring[0]));  /* ROLLINS */
+
+	GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR1, 0);
+
+	// init Tx indeces and pkt counter
+	gp->tx_next_in = gp->tx_next_out = 0;
+	gp->tx_count = 0;
+}
+
+static void reset_rx(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int i;
+
+	abort(dev, sdcmrAR);
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		gp->rx_ring[i].next =
+		    gp->rx_ring_dma + sizeof(gt64240_rd_t) * (i + 1);
+		gp->rx_ring[i].buff_ptr = gp->rx_buff_dma + i * PKT_BUF_SZ;
+		gp->rx_ring[i].buff_sz = PKT_BUF_SZ;
+		gp->rx_ring[i].byte_cnt = 0;	/* just for debug printk's */
+		// Give ownership to device, set first and last, enable interrupt
+		gp->rx_ring[i].cmdstat =
+		    (uint32_t) (rxFirst | rxLast | rxOwn | rxEI);
+		if (gt64240_debug > 4)
+			dump_rx_desc(dev, i);
+	}
+	/* Wrap the ring. */
+	gp->rx_ring[i - 1].next = gp->rx_ring_dma;
+	if (gt64240_debug > 4)
+		dump_rx_desc(dev, i - 1);
+
+	// Setup only the lowest priority RxFDP and RxCDP regs
+	for (i = 0; i < 4; i++) {
+		if (i == 0) {
+			GT64240ETH_WRITE(gp, GT64240_ETH_1ST_RX_DESC_PTR0,
+					 gp->rx_ring_dma);
+			GT64240ETH_WRITE(gp, GT64240_ETH_CURR_RX_DESC_PTR0,
+					 gp->rx_ring_dma);
+		} else {
+			GT64240ETH_WRITE(gp,
+					 GT64240_ETH_1ST_RX_DESC_PTR0 +
+					 i * 4, 0);
+			GT64240ETH_WRITE(gp,
+					 GT64240_ETH_CURR_RX_DESC_PTR0 +
+					 i * 4, 0);
+		}
+	}
+
+	// init Rx NextOut index
+	gp->rx_next_out = 0;
+}
+
+
+static int gt64240_init(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	u32 ciu;
+
+	if (gt64240_debug > 3) {
+		printk("%s: gt64240_init: dev=%p\n", dev->name, dev);
+		printk("%s: gt64240_init: scs0_lo=%04x, scs0_hi=%04x\n",
+		       dev->name, GT64240_READ(0x008),
+		       GT64240_READ(0x010));
+		printk("%s: gt64240_init: scs1_lo=%04x, scs1_hi=%04x\n",
+		       dev->name, GT64240_READ(0x208),
+		       GT64240_READ(0x210));
+		printk("%s: gt64240_init: scs2_lo=%04x, scs2_hi=%04x\n",
+		       dev->name, GT64240_READ(0x018),
+		       GT64240_READ(0x020));
+		printk("%s: gt64240_init: scs3_lo=%04x, scs3_hi=%04x\n",
+		       dev->name, GT64240_READ(0x218),
+		       GT64240_READ(0x220));
+	}
+	// Stop and disable Port
+	hard_stop(dev);
+
+	GT64240_WRITE(COMM_UNIT_INTERRUPT_MASK, 0x07070777);	/*+prk21aug01 */
+	if (gt64240_debug > 2)
+		printk
+		    ("%s: gt64240_init: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n",
+		     dev->name, GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE),
+		     GT64240_READ(COMM_UNIT_INTERRUPT_MASK),
+		     GT64240_READ(COMM_UNIT_ERROR_ADDRESS));
+
+	// Set-up hash table
+	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear it
+	gp->hash_mode = 0;
+	// Add a single entry to hash table - our ethernet address
+	gt64240_add_hash_entry(dev, dev->dev_addr);
+	// Set-up DMA ptr to hash table
+	GT64240ETH_WRITE(gp, GT64240_ETH_HASH_TBL_PTR, gp->hash_table_dma);
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Hash Tbl Ptr=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_HASH_TBL_PTR));
+
+	// Setup Tx
+	reset_tx(dev);
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Curr Tx Desc Ptr0=%x\n",
+		       dev->name, GT64240ETH_READ(gp,
+						  GT64240_ETH_CURR_TX_DESC_PTR0));
+
+	// Setup Rx
+	reset_rx(dev);
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: 1st/Curr Rx Desc Ptr0=%x/%x\n",
+		       dev->name, GT64240ETH_READ(gp,
+						  GT64240_ETH_1ST_RX_DESC_PTR0),
+		       GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0));
+
+	if (gt64240_debug > 3)
+		dump_MII(dev);
+	write_MII(dev, 0, 0x8000);	/* force a PHY reset -- self-clearing! */
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: PhyAD=%x\n", dev->name,
+		       GT64240_READ(GT64240_ETH_PHY_ADDR_REG));
+
+	// setup DMA
+	// We want the Rx/Tx DMA to write/read data to/from memory in
+	// Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
+#ifdef DESC_DATA_BE
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG,
+			 (0xf << sdcrRCBit) | sdcrRIFB | (3 <<
+							  sdcrBSZBit));
+#else
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG, sdcrBLMR | sdcrBLMT |
+//-                  (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
+			 (0xf << sdcrRCBit) | sdcrRIFB | (2 <<
+							  sdcrBSZBit));
+#endif
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: SDMA Config=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_SDMA_CONFIG));
+
+#if 0
+	// start Rx DMA
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
+#endif
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: SDMA Cmd =%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM));
+
+#if 1
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, PORT_CONFIG);
+#endif
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Port Config=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
+
+	/*
+	 * Disable all Type-of-Service queueing. All Rx packets will be
+	 * treated normally and will be sent to the lowest priority
+	 * queue.
+	 *
+	 * Disable flow-control for now. FIX! support flow control?
+	 */
+
+#if 1
+	// clear all the MIB ctr regs
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT,
+			 EXT_CONFIG_CLEAR);
+	read_mib_counters(gp);
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT,
+			 EXT_CONFIG_CLEAR | pcxrMIBclrMode);
+
+#endif
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Port Config Ext=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG_EXT));
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Port Command=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_PORT_COMMAND));
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_COMMAND, 0x0);
+
+	netif_start_queue(dev);
+
+	/* enable the port */
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG,
+			 (PORT_CONFIG | pcrEN));
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_init: Port Config=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
+#if 1
+	// start Rx DMA
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
+#endif
+
+
+	// enable interrupts
+	enable_ether_irq(dev);
+
+//---    gp->last_psr |= psrLink;   /* KLUDGE ALERT */
+
+	// we should now be receiving frames
+	return 0;
+}
+
+
+static int gt64240_open(struct net_device *dev)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_open: dev=%p\n", dev->name, dev);
+
+	if ((retval = request_irq(dev->irq, &gt64240_interrupt,
+				  SA_SHIRQ, dev->name, dev))) {
+		printk("%s: unable to get IRQ %d\n", dev->name, dev->irq);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	// Initialize and startup the GT-64240 ethernet port
+	if ((retval = gt64240_init(dev))) {
+		printk("%s: error in gt64240_open\n", dev->name);
+		free_irq(dev->irq, dev);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_open: Initialization done.\n",
+		       dev->name);
+
+	return 0;
+}
+
+static int gt64240_close(struct net_device *dev)
+{
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_close: dev=%p\n", dev->name, dev);
+
+	// stop the device
+	if (netif_device_present(dev)) {
+		netif_stop_queue(dev);
+		hard_stop(dev);
+	}
+
+	free_irq(dev->irq, dev);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef GT64240_NAPI
+/*
+ * Function will release Tx skbs which are now complete
+ */
+static void gt64240_tx_fill(struct net_device *netdev, u32 status)
+{
+	struct gt64240_private *gp =
+	    (struct gt64240_private *) netdev->priv;
+	int nextOut, cdp;
+	gt64240_td_t *td;
+	u32 cmdstat;
+
+	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0)
+	       - gp->tx_ring_dma) / sizeof(gt64240_td_t);
+
+	for (nextOut = gp->tx_next_out; nextOut != cdp;
+	     nextOut = (nextOut + 1) % TX_RING_SIZE) {
+		if (--gp->intr_work_done == 0)
+			break;
+
+		td = &gp->tx_ring[nextOut];
+		cmdstat = td->cmdstat;
+
+		if (cmdstat & (u32) txOwn)
+			break;
+
+		if (gp->tx_full) {
+			gp->tx_full = 0;
+			if (gp->last_psr & psrLink) {
+				netif_wake_queue(netdev);
+			}
+		}
+		// decrement tx ring buffer count
+		if (gp->tx_count)
+			gp->tx_count--;
+
+		// free the skb
+		if (gp->tx_skbuff[nextOut]) {
+			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
+			gp->tx_skbuff[nextOut] = NULL;
+		}
+	}
+
+	gp->tx_next_out = nextOut;
+
+	if ((status & icrTxEndLow) && gp->tx_count != 0)
+		// we must restart the DMA
+		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
+				 sdcmrERD | sdcmrTXDL);
+}
+
+/*
+ * Main function for NAPI
+ */
+static int gt64240_poll(struct net_device *netdev, int *budget)
+{
+	struct gt64240_private *gp =
+	    (struct gt64240_private *) netdev->priv;
+	unsigned long flags;
+	int done = 1, orig_budget, work_done;
+	u32 intMask, status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
+
+	spin_lock_irqsave(&gp->lock, flags);
+	gt64240_tx_fill(netdev, status);
+
+	if (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0) !=
+	    gp->rx_next_out) {
+		orig_budget = *budget;
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+
+		work_done = gt64240_rx(netdev, status, orig_budget);
+		*budget -= work_done;
+		netdev->quota -= work_done;
+		if (work_done >= orig_budget)
+			done = 0;
+		if (done) {
+			__netif_rx_complete(netdev);
+			enable_ether_irq(netdev);
+		}
+	}
+
+	spin_unlock_irqrestore(&gp->lock, flags);
+}
+#endif
+
+static int gt64240_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	unsigned long flags;
+	int nextIn;
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+	nextIn = gp->tx_next_in;
+
+	if (gt64240_debug > 3) {
+		printk("%s: gt64240_tx: nextIn=%d.\n", dev->name, nextIn);
+	}
+
+	if (gp->tx_count >= TX_RING_SIZE) {
+		printk("%s: Tx Ring full, pkt dropped.\n", dev->name);
+		gp->stats.tx_dropped++;
+		spin_unlock_irqrestore(&gp->lock, flags);
+		return 1;
+	}
+
+	if (!(gp->last_psr & psrLink)) {
+		printk("%s: gt64240_tx: Link down, pkt dropped.\n",
+		       dev->name);
+		gp->stats.tx_dropped++;
+		spin_unlock_irqrestore(&gp->lock, flags);
+//---   dump_MII(dev);          /* KLUDGE ALERT !!! */
+		return 1;
+	}
+
+	if (gp->tx_ring[nextIn].cmdstat & txOwn) {
+		printk
+		    ("%s: gt64240_tx: device owns descriptor, pkt dropped.\n",
+		     dev->name);
+		gp->stats.tx_dropped++;
+		// stop the queue, so Tx timeout can fix it
+		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&gp->lock, flags);
+		return 1;
+	}
+	// Prepare the Descriptor at tx_next_in
+	gp->tx_skbuff[nextIn] = skb;
+	gp->tx_ring[nextIn].byte_cnt = skb->len;
+	gp->tx_ring[nextIn].buff_ptr = virt_to_phys(skb->data);
+
+	// make sure packet gets written back to memory
+	dma_cache_wback_inv((unsigned long) (skb->data), skb->len);
+	mb();
+
+	// Give ownership to device, set first and last desc, enable interrupt
+	// Setting of ownership bit must be *last*!
+	gp->tx_ring[nextIn].cmdstat =
+	    txOwn | txGenCRC | txEI | txPad | txFirst | txLast;
+
+	if (gt64240_debug > 5) {
+		dump_tx_desc(dev, nextIn);
+		dump_skb(dev, skb);
+	}
+	// increment tx_next_in with wrap
+	gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
+
+//+prk20aug01:
+	if (0) {		/* ROLLINS */
+		GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,
+				 virt_to_phys(&gp->tx_ring[nextIn]));
+	}
+
+	if (gt64240_debug > 3) {	/*+prk17aug01 */
+		printk
+		    ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n",
+		     dev->name, GT64240ETH_READ(gp,
+						GT64240_ETH_CURR_TX_DESC_PTR0),
+		     GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS));
+	}
+	// If DMA is stopped, restart
+	if (!((GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS)) & psrTxLow)) {
+		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
+				 sdcmrERD | sdcmrTXDL);
+	}
+
+	if (gt64240_debug > 3) {	/*+prk17aug01 */
+		printk
+		    ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n",
+		     dev->name, GT64240ETH_READ(gp,
+						GT64240_ETH_CURR_TX_DESC_PTR0),
+		     GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS));
+	}
+	// increment count and stop queue if full
+	if (++gp->tx_count >= TX_RING_SIZE) {
+		gp->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&gp->lock, flags);
+
+	return 0;
+}
+
+
+static int
+#ifdef GT64240_NAPI
+gt64240_rx(struct net_device *dev, u32 status, int budget)
+#else
+gt64240_rx(struct net_device *dev, u32 status)
+#endif
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	struct sk_buff *skb;
+	int pkt_len, nextOut, cdp;
+	gt64240_rd_t *rd;
+	u32 cmdstat;
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_rx: dev=%p, status=%x\n",
+		       dev->name, dev, status);
+
+	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0)
+	       - gp->rx_ring_dma) / sizeof(gt64240_rd_t);
+
+	// Continue until we reach the current descriptor pointer
+	for (nextOut = gp->rx_next_out; nextOut != cdp;
+	     nextOut = (nextOut + 1) % RX_RING_SIZE) {
+
+#ifdef GT64240_NAPI
+		if (budget <= 0)
+			break;
+
+		budget--;
+#endif
+
+		if (--gp->intr_work_done == 0)
+			break;
+
+		if (gt64240_debug > 4)
+			dump_rx_desc(dev, nextOut);
+
+		rd = &gp->rx_ring[nextOut];
+		cmdstat = rd->cmdstat;
+
+		if (gt64240_debug > 3)
+			printk("%s: isr: Rx desc cmdstat=%x, nextOut=%d\n",
+			       dev->name, cmdstat, nextOut);
+
+		if (cmdstat & (u32) rxOwn) {
+			if (gt64240_debug > 2)
+				printk
+				    ("%s: gt64240_rx: device owns descriptor!\n",
+				     dev->name);
+			// DMA is not finished updating descriptor???
+			// Leave and come back later to pick-up where we left off.
+			break;
+		}
+		// must be first and last (ie only) buffer of packet
+		if (!(cmdstat & (u32) rxFirst)
+		    || !(cmdstat & (u32) rxLast)) {
+			printk
+			    ("%s: gt64240_rx: desc not first and last!\n",
+			     dev->name);
+			cmdstat |= (u32) rxOwn;
+			rd->cmdstat = cmdstat;
+			continue;
+		}
+		// Drop this received pkt if there were any errors
+		if ((cmdstat & (u32) rxErrorSummary)
+		    || (status & icrRxError)) {
+			// update the detailed rx error counters that are not covered
+			// by the MIB counters.
+			if (cmdstat & (u32) rxOverrun)
+				gp->stats.rx_fifo_errors++;
+			cmdstat |= (u32) rxOwn;
+			rd->cmdstat = cmdstat;
+			continue;
+		}
+
+		pkt_len = rd->byte_cnt;
+
+		/* Create new skb. */
+//      skb = dev_alloc_skb(pkt_len+2);
+		skb = dev_alloc_skb(1538);
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n",
+			       dev->name);
+			gp->stats.rx_dropped++;
+			cmdstat |= (u32) rxOwn;
+			rd->cmdstat = cmdstat;
+			continue;
+		}
+		skb->dev = dev;
+		skb_reserve(skb, 2);	/* 16 byte IP header align */
+		memcpy(skb_put(skb, pkt_len),
+		       &gp->rx_buff[nextOut * PKT_BUF_SZ], pkt_len);
+		skb->protocol = eth_type_trans(skb, dev);
+		if (gt64240_debug > 4)	/* will probably Oops! */
+			dump_data(dev, &gp->rx_buff[nextOut * PKT_BUF_SZ],
+				  pkt_len);
+		if (gt64240_debug > 4)
+			dump_skb(dev, skb);
+
+		/* NIC performed some checksum computation */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+#ifdef GT64240_NAPI
+		netif_receive_skb(skb);
+#else
+		netif_rx(skb);	/* pass the packet to upper layers */
+#endif
+
+		// now we can release ownership of this desc back to device
+		cmdstat |= (u32) rxOwn;
+		rd->cmdstat = cmdstat;
+
+		dev->last_rx = jiffies;
+	}
+
+	if (gt64240_debug > 3 && nextOut == gp->rx_next_out)
+		printk("%s: gt64240_rx: RxCDP did not increment?\n",
+		       dev->name);
+
+	gp->rx_next_out = nextOut;
+	return 0;
+}
+
+
+static void gt64240_tx_complete(struct net_device *dev, u32 status)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int nextOut, cdp;
+	gt64240_td_t *td;
+	u32 cmdstat;
+
+	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0)
+	       - gp->tx_ring_dma) / sizeof(gt64240_td_t);
+
+	if (gt64240_debug > 3) {	/*+prk17aug01 */
+		nextOut = gp->tx_next_out;
+		printk
+		    ("%s: tx_complete: TX_PTR0=0x%08x, cdp=%d. nextOut=%d.\n",
+		     dev->name, GT64240ETH_READ(gp,
+						GT64240_ETH_CURR_TX_DESC_PTR0),
+		     cdp, nextOut);
+		td = &gp->tx_ring[nextOut];
+	}
+
+/*** NEED to check and CLEAR these errors every time thru here: ***/
+	if (gt64240_debug > 2) {
+		if (GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE))
+			printk
+			    ("%s: gt64240_tx_complete: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n",
+			     dev->name,
+			     GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE),
+			     GT64240_READ(COMM_UNIT_INTERRUPT_MASK),
+			     GT64240_READ(COMM_UNIT_ERROR_ADDRESS));
+		GT64240_WRITE(COMM_UNIT_INTERRUPT_CAUSE, 0);
+	}
+	// Continue until we reach the current descriptor pointer
+	for (nextOut = gp->tx_next_out; nextOut != cdp;
+	     nextOut = (nextOut + 1) % TX_RING_SIZE) {
+
+		if (--gp->intr_work_done == 0)
+			break;
+
+		td = &gp->tx_ring[nextOut];
+		cmdstat = td->cmdstat;
+
+		if (cmdstat & (u32) txOwn) {
+			// DMA is not finished writing descriptor???
+			// Leave and come back later to pick-up where we left off.
+			break;
+		}
+		// increment Tx error stats
+		if (cmdstat & (u32) txErrorSummary) {
+			if (gt64240_debug > 2)
+				printk
+				    ("%s: tx_complete: Tx error, cmdstat = %x\n",
+				     dev->name, cmdstat);
+			gp->stats.tx_errors++;
+			if (cmdstat & (u32) txReTxLimit)
+				gp->stats.tx_aborted_errors++;
+			if (cmdstat & (u32) txUnderrun)
+				gp->stats.tx_fifo_errors++;
+			if (cmdstat & (u32) txLateCollision)
+				gp->stats.tx_window_errors++;
+		}
+
+		if (cmdstat & (u32) txCollision)
+			gp->stats.collisions +=
+			    (unsigned long) ((cmdstat & txReTxCntMask) >>
+					     txReTxCntBit);
+
+		// Wake the queue if the ring was full
+		if (gp->tx_full) {
+			gp->tx_full = 0;
+			if (gp->last_psr & psrLink) {
+				netif_wake_queue(dev);
+			}
+		}
+		// decrement tx ring buffer count
+		if (gp->tx_count)
+			gp->tx_count--;
+
+		// free the skb
+		if (gp->tx_skbuff[nextOut]) {
+			if (gt64240_debug > 3)
+				printk
+				    ("%s: tx_complete: good Tx, skb=%p\n",
+				     dev->name, gp->tx_skbuff[nextOut]);
+			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
+			gp->tx_skbuff[nextOut] = NULL;
+		} else {
+			printk("%s: tx_complete: no skb!\n", dev->name);
+		}
+	}
+
+	gp->tx_next_out = nextOut;
+
+	if ((status & icrTxEndLow) && gp->tx_count != 0) {
+		// we must restart the DMA
+		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
+				 sdcmrERD | sdcmrTXDL);
+	}
+}
+
+
+static void gt64240_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	u32 status;
+
+	if (dev == NULL) {
+		printk("%s: isr: null dev ptr\n", dev->name);
+		return;
+	}
+
+	spin_lock(&gp->lock);
+
+	if (gt64240_debug > 3)
+		printk("%s: isr: entry\n", dev->name);
+
+	gp->intr_work_done = max_interrupt_work;
+
+	while (gp->intr_work_done > 0) {
+
+		status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
+#ifdef GT64240_NAPI
+		/* dont ack Rx interrupts */
+		if (!(status & icrRxBuffer))
+			GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
+#else
+		// ACK interrupts
+		GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
+#endif
+
+		if (gt64240_debug > 3)
+			printk("%s: isr: work=%d., icr=%x\n", dev->name,
+			       gp->intr_work_done, status);
+
+		if ((status & icrEtherIntSum) == 0) {
+			if (!(status &
+			      (icrTxBufferLow | icrTxBufferHigh |
+			       icrRxBuffer))) {
+				/* exit from the while() loop */
+				break;
+			}
+		}
+
+		if (status & icrMIIPhySTC) {
+			u32 psr =
+			    GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS);
+			if (gp->last_psr != psr) {
+				printk("%s: port status: 0x%08x\n",
+				       dev->name, psr);
+				printk
+				    ("%s:    %s MBit/s, %s-duplex, flow-control %s, link is %s,\n",
+				     dev->name,
+				     psr & psrSpeed ? "100" : "10",
+				     psr & psrDuplex ? "full" : "half",
+				     psr & psrFctl ? "disabled" :
+				     "enabled",
+				     psr & psrLink ? "up" : "down");
+				printk
+				    ("%s:    TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n",
+				     dev->name,
+				     psr & psrTxLow ? "running" :
+				     "stopped",
+				     psr & psrTxHigh ? "running" :
+				     "stopped",
+				     psr & psrTxInProg ? "on" : "off");
+
+				if ((psr & psrLink) && !gp->tx_full &&
+				    netif_queue_stopped(dev)) {
+					printk
+					    ("%s: isr: Link up, waking queue.\n",
+					     dev->name);
+					netif_wake_queue(dev);
+				} else if (!(psr & psrLink)
+					   && !netif_queue_stopped(dev)) {
+					printk
+					    ("%s: isr: Link down, stopping queue.\n",
+					     dev->name);
+					netif_stop_queue(dev);
+				}
+
+				gp->last_psr = psr;
+			}
+		}
+
+		if (status & (icrTxBufferLow | icrTxEndLow))
+			gt64240_tx_complete(dev, status);
+
+		if (status & icrRxBuffer) {
+#ifdef GT64240_NAPI
+			if (netif_rx_schedule_prep(dev)) {
+				disable_ether_irq(dev);
+				__netif_rx_schedule(dev);
+			}
+#else
+			gt64240_rx(dev, status);
+#endif
+		}
+		// Now check TX errors (RX errors were handled in gt64240_rx)
+		if (status & icrTxErrorLow) {
+			printk("%s: isr: Tx resource error\n", dev->name);
+		}
+
+		if (status & icrTxUdr) {
+			printk("%s: isr: Tx underrun error\n", dev->name);
+		}
+	}
+
+	if (gp->intr_work_done == 0) {
+		// ACK any remaining pending interrupts
+		GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
+		if (gt64240_debug > 3)
+			printk("%s: isr: hit max work\n", dev->name);
+	}
+
+	if (gt64240_debug > 3)
+		printk("%s: isr: exit, icr=%x\n",
+		       dev->name, GT64240ETH_READ(gp,
+						  GT64240_ETH_INT_CAUSE));
+
+	spin_unlock(&gp->lock);
+}
+
+
+static void gt64240_tx_timeout(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+
+	if (!(gp->last_psr & psrLink)) {
+		spin_unlock_irqrestore(&gp->lock, flags);
+	} else {
+		printk("======------> gt64240_tx_timeout: %d jiffies \n",
+		       GT64240ETH_TX_TIMEOUT);
+
+		disable_ether_irq(dev);
+		spin_unlock_irqrestore(&gp->lock, flags);
+		reset_tx(dev);
+		enable_ether_irq(dev);
+
+		netif_wake_queue(dev);
+	}
+}
+
+
+static void gt64240_set_rx_mode(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	unsigned long flags;
+	struct dev_mc_list *mcptr;
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_set_rx_mode: dev=%p, flags=%x\n",
+		       dev->name, dev, dev->flags);
+
+	// stop the Receiver DMA
+	abort(dev, sdcmrAR);
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+	if (dev->flags & IFF_PROMISC)
+		GT64240ETH_SETBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM);
+	else
+		GT64240ETH_CLRBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM);
+/*
+	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG,
+		(PORT_CONFIG | pcrPM | pcrEN));
+*/
+
+	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear hash table
+	// Add our ethernet address
+	gt64240_add_hash_entry(dev, dev->dev_addr);
+	if (dev->mc_count) {
+		for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
+			if (gt64240_debug > 2) {
+				printk("%s: gt64240_set_rx_mode: addr=\n",
+				       dev->name);
+				dump_hw_addr(mcptr->dmi_addr);
+			}
+			gt64240_add_hash_entry(dev, mcptr->dmi_addr);
+		}
+	}
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_set_rx: Port Config=%x\n", dev->name,
+		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
+
+	// restart Rx DMA
+	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
+
+	spin_unlock_irqrestore(&gp->lock, flags);
+}
+
+static struct net_device_stats *gt64240_get_stats(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	unsigned long flags;
+
+	if (gt64240_debug > 3)
+		printk("%s: gt64240_get_stats: dev=%p\n", dev->name, dev);
+
+	if (netif_device_present(dev)) {
+		spin_lock_irqsave(&gp->lock, flags);
+		update_stats(gp);
+		spin_unlock_irqrestore(&gp->lock, flags);
+	}
+
+	return &gp->stats;
+}
diff -urN linux-2.4.23-bk1/drivers/net/gt64240eth.h linux-2.4.23-bk2/drivers/net/gt64240eth.h
--- linux-2.4.23-bk1/drivers/net/gt64240eth.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/gt64240eth.h	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,406 @@
+/* $Id: gt64240eth.h.rca 1.1 Tue Mar 11 10:39:26 2003 doucett1 Experimental $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Patton Electronics Company
+ * Copyright (C) 2002 Momentum Computer
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or support@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Ethernet driver definitions for the MIPS GT96100 Advanced
+ * Communication Controller.
+ * 
+ * Modified for the Marvellous GT64240 Retarded Communication Controller.
+ *
+ */
+#ifndef _GT64240ETH_H
+#define _GT64240ETH_H
+
+#include "../../arch/mips/momentum/ocelot_g/gt64240.h"
+
+#define ETHERNET_PORTS_DIFFERENCE_OFFSETS	0x400
+
+/* Translate those weanie names from Galileo/VxWorks header files: */
+
+#define GT64240_MRR                    MAIN_ROUTING_REGISTER
+#define GT64240_CIU_ARBITER_CONFIG     COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
+#define GT64240_CIU_ARBITER_CONTROL    COMM_UNIT_ARBITER_CONTROL
+#define GT64240_MAIN_LOW_CAUSE         LOW_INTERRUPT_CAUSE_REGISTER
+#define GT64240_MAIN_HIGH_CAUSE        HIGH_INTERRUPT_CAUSE_REGISTER
+#define GT64240_CPU_LOW_MASK           CPU_INTERRUPT_MASK_REGISTER_LOW
+#define GT64240_CPU_HIGH_MASK          CPU_INTERRUPT_MASK_REGISTER_HIGH
+#define GT64240_CPU_SELECT_CAUSE       CPU_SELECT_CAUSE_REGISTER
+
+#define GT64240_ETH_PHY_ADDR_REG       ETHERNET_PHY_ADDRESS_REGISTER
+#define GT64240_ETH_PORT_CONFIG        ETHERNET0_PORT_CONFIGURATION_REGISTER
+#define GT64240_ETH_PORT_CONFIG_EXT    ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
+#define GT64240_ETH_PORT_COMMAND       ETHERNET0_PORT_COMMAND_REGISTER
+#define GT64240_ETH_PORT_STATUS        ETHERNET0_PORT_STATUS_REGISTER
+#define GT64240_ETH_IO_SIZE            ETHERNET_PORTS_DIFFERENCE_OFFSETS
+#define GT64240_ETH_SMI_REG            ETHERNET_SMI_REGISTER
+#define GT64240_ETH_MIB_COUNT_BASE     ETHERNET0_MIB_COUNTER_BASE
+#define GT64240_ETH_SDMA_CONFIG        ETHERNET0_SDMA_CONFIGURATION_REGISTER
+#define GT64240_ETH_SDMA_COMM          ETHERNET0_SDMA_COMMAND_REGISTER
+#define GT64240_ETH_INT_MASK           ETHERNET0_INTERRUPT_MASK_REGISTER
+#define GT64240_ETH_INT_CAUSE          ETHERNET0_INTERRUPT_CAUSE_REGISTER
+#define GT64240_ETH_CURR_TX_DESC_PTR0  ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_CURR_TX_DESC_PTR1  ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
+#define GT64240_ETH_1ST_RX_DESC_PTR0   ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_CURR_RX_DESC_PTR0  ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_HASH_TBL_PTR       ETHERNET0_HASH_TABLE_POINTER_REGISTER
+
+/* Turn on NAPI by default */
+
+#define	GT64240_NAPI			1
+
+/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
+/* (Board-specific to the DSL3224 Rev A board ONLY!)                    */
+#define D3224_MPP_CTRL0_SETTING		0x66669900
+#define D3224_MPP_CTRL1_SETTING		0x00000000
+#define D3224_MPP_CTRL2_SETTING		0x00887700
+#define D3224_MPP_CTRL3_SETTING		0x00000044
+#define D3224_GPP_IO_CTRL_SETTING	0x0000e800
+#define D3224_GPP_LEVEL_CTRL_SETTING	0xf001f703
+#define D3224_GPP_VALUE_SETTING		0x00000000
+
+/* Keep the ring sizes a power of two for efficiency. */
+//-#define TX_RING_SIZE	16
+#define TX_RING_SIZE	64	/* TESTING !!! */
+#define RX_RING_SIZE	32
+#define PKT_BUF_SZ	1536	/* Size of each temporary Rx buffer.*/
+
+#define RX_HASH_TABLE_SIZE 16384
+#define HASH_HOP_NUMBER 12
+
+#define NUM_INTERFACES 3
+
+#define GT64240ETH_TX_TIMEOUT HZ/4
+
+#define MIPS_GT64240_BASE 0xf4000000
+#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
+#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
+#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
+
+#if defined(CONFIG_MIPS_DSL3224)
+#define GT64240_ETHER0_IRQ 4
+#define GT64240_ETHER1_IRQ 4
+#else
+#define GT64240_ETHER0_IRQ -1
+#define GT64240_ETHER1_IRQ -1
+#endif
+
+#define REV_GT64240  0x1
+#define REV_GT64240A 0x10
+
+#define GT64240ETH_READ(gp, offset) \
+    GT_READ_DATA((gp)->port_offset + (offset))
+
+#define GT64240ETH_WRITE(gp, offset, data) \
+    GT_WRITE((gp)->port_offset + (offset), (data))
+
+#define GT64240ETH_SETBIT(gp, offset, bits) \
+    GT64240ETH_WRITE((gp), (offset), GT64240ETH_READ((gp), (offset)) | (bits))
+
+#define GT64240ETH_CLRBIT(gp, offset, bits) \
+    GT64240ETH_WRITE((gp), (offset), GT64240ETH_READ((gp), (offset)) & ~(bits))
+
+#define GT64240_WRITE(ofs, data)	GT_WRITE((ofs), (data))
+
+#define GT64240_READ(ofs)		GT_READ_DATA((ofs))
+
+/* Bit definitions of the SMI Reg */
+enum {
+    smirDataMask = 0xffff,
+    smirPhyAdMask = 0x1f<<16,
+    smirPhyAdBit = 16,
+    smirRegAdMask = 0x1f<<21,
+    smirRegAdBit = 21,
+    smirOpCode = 1<<26,
+    smirReadValid = 1<<27,
+    smirBusy = 1<<28
+};
+
+/* Bit definitions of the Port Config Reg */
+enum pcr_bits {
+    pcrPM = 1 << 0,
+    pcrRBM = 1 << 1,
+    pcrPBF = 1 << 2,
+    pcrEN = 1 << 7,
+    pcrLPBKMask = 0x3<<8,
+    pcrLPBKBit = 1 << 8,
+    pcrFC = 1<<10,
+    pcrHS = 1<<12,
+    pcrHM = 1<<13,
+    pcrHDM = 1<<14,
+    pcrHD = 1<<15,
+    pcrISLMask = 0x7<<28,
+    pcrISLBit = 28,
+    pcrACCS = 1<<31
+};
+
+/* Bit definitions of the Port Config Extend Reg */
+enum pcxr_bits {
+    pcxrIGMP = 1,
+    pcxrSPAN = 2,
+    pcxrPAR = 4,
+    pcxrPRIOtxMask = 0x7<<3,
+    pcxrPRIOtxBit = 3,
+    pcxrPRIOrxMask = 0x3<<6,
+    pcxrPRIOrxBit = 6,
+    pcxrPRIOrxOverride = 1<<8,
+    pcxrDPLXen = 1<<9,
+    pcxrFCTLen = 1<<10,
+    pcxrFLP = 1<<11,
+    pcxrFCTL = 1<<12,
+    pcxrMFLMask = 0x3<<14,
+    pcxrMFLBit = 14,
+    pcxrMIBclrMode = 1<<16,
+    pcxrSpeed = 1<<18,
+    pcxrSpeeden = 1<<19,
+    pcxrRMIIen = 1<<20,
+    pcxrDSCPen = 1<<21
+};
+
+/* Bit definitions of the Port Command Reg */
+enum pcmr_bits {
+    pcmrFJ = 1<<15
+};
+
+
+/* Bit definitions of the Port Status Reg */
+enum psr_bits {
+    psrSpeed = 1,
+    psrDuplex = 2,
+    psrFctl = 4,
+    psrLink = 8,
+    psrPause = 1<<4,
+    psrTxLow = 1<<5,
+    psrTxHigh = 1<<6,
+    psrTxInProg = 1<<7
+};
+
+/* Bit definitions of the SDMA Config Reg */
+enum sdcr_bits {
+    sdcrRCMask = 0xf<<2,
+    sdcrRCBit = 2,
+    sdcrBLMR = 1<<6,
+    sdcrBLMT = 1<<7,
+    sdcrPOVR = 1<<8,
+    sdcrRIFB = 1<<9,
+    sdcrBSZMask = 0x3<<12,
+    sdcrBSZBit = 12
+};
+
+/* Bit definitions of the SDMA Command Reg */
+enum sdcmr_bits {
+    sdcmrERD = 1<<7,
+    sdcmrAR = 1<<15,
+    sdcmrSTDH = 1<<16,
+    sdcmrSTDL = 1<<17,
+    sdcmrTXDH = 1<<23,
+    sdcmrTXDL = 1<<24,
+    sdcmrAT = 1<<31
+};
+
+/* Bit definitions of the Interrupt Cause Reg */
+enum icr_bits {
+    icrRxBuffer = 1,
+    icrTxBufferHigh = 1<<2,
+    icrTxBufferLow = 1<<3,
+    icrTxEndHigh = 1<<6,
+    icrTxEndLow = 1<<7,
+    icrRxError = 1<<8,
+    icrTxErrorHigh = 1<<10,
+    icrTxErrorLow = 1<<11,
+    icrRxOVR = 1<<12,
+    icrTxUdr = 1<<13,
+    icrRxBufferQ0 = 1<<16,
+    icrRxBufferQ1 = 1<<17,
+    icrRxBufferQ2 = 1<<18,
+    icrRxBufferQ3 = 1<<19,
+    icrRxErrorQ0 = 1<<20,
+    icrRxErrorQ1 = 1<<21,
+    icrRxErrorQ2 = 1<<22,
+    icrRxErrorQ3 = 1<<23,
+    icrMIIPhySTC = 1<<28,
+    icrSMIdone = 1<<29,
+    icrEtherIntSum = 1<<31
+};
+
+
+/* The Rx and Tx descriptor lists. */
+#ifdef __LITTLE_ENDIAN
+typedef struct {
+    u32 cmdstat;
+    u16 reserved;  //-prk21aug01    u32 reserved:16;
+    u16 byte_cnt;  //-prk21aug01    u32 byte_cnt:16;
+    u32 buff_ptr;
+    u32 next;
+} gt64240_td_t;
+
+typedef struct {
+    u32 cmdstat;
+    u16 byte_cnt;  //-prk21aug01    u32 byte_cnt:16;
+    u16 buff_sz;   //-prk21aug01    u32 buff_sz:16;
+    u32 buff_ptr;
+    u32 next;
+} gt64240_rd_t;
+#elif defined(__BIG_ENDIAN)
+typedef struct {
+    u16 byte_cnt;  //-prk21aug01    u32 byte_cnt:16;
+    u16 reserved;  //-prk21aug01    u32 reserved:16;
+    u32 cmdstat;
+    u32 next;
+    u32 buff_ptr;
+} gt64240_td_t;
+
+typedef struct {
+    u16 buff_sz;   //-prk21aug01    u32 buff_sz:16;
+    u16 byte_cnt;  //-prk21aug01    u32 byte_cnt:16;
+    u32 cmdstat;
+    u32 next;
+    u32 buff_ptr;
+} gt64240_rd_t;
+#else
+#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
+#endif
+
+
+/* Values for the Tx command-status descriptor entry. */
+enum td_cmdstat {
+    txOwn = 1<<31,
+    txAutoMode = 1<<30,
+    txEI = 1<<23,
+    txGenCRC = 1<<22,
+    txPad = 1<<18,
+    txFirst = 1<<17,
+    txLast = 1<<16,
+    txErrorSummary = 1<<15,
+    txReTxCntMask = 0x0f<<10,
+    txReTxCntBit = 10,
+    txCollision = 1<<9,
+    txReTxLimit = 1<<8,
+    txUnderrun = 1<<6,
+    txLateCollision = 1<<5
+};
+
+
+/* Values for the Rx command-status descriptor entry. */
+enum rd_cmdstat {
+    rxOwn = 1<<31,
+    rxAutoMode = 1<<30,
+    rxEI = 1<<23,
+    rxFirst = 1<<17,
+    rxLast = 1<<16,
+    rxErrorSummary = 1<<15,
+    rxIGMP = 1<<14,
+    rxHashExpired = 1<<13,
+    rxMissedFrame = 1<<12,
+    rxFrameType = 1<<11,
+    rxShortFrame = 1<<8,
+    rxMaxFrameLen = 1<<7,
+    rxOverrun = 1<<6,
+    rxCollision = 1<<4,
+    rxCRCError = 1
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+    hteValid = 1,
+    hteSkip = 2,
+    hteRD = 4
+};
+
+// The MIB counters
+typedef struct {
+    u32 byteReceived;
+    u32 byteSent;
+    u32 framesReceived;
+    u32 framesSent;
+    u32 totalByteReceived;
+    u32 totalFramesReceived;
+    u32 broadcastFramesReceived;
+    u32 multicastFramesReceived;
+    u32 cRCError;
+    u32 oversizeFrames;
+    u32 fragments;
+    u32 jabber;
+    u32 collision;
+    u32 lateCollision;
+    u32 frames64;
+    u32 frames65_127;
+    u32 frames128_255;
+    u32 frames256_511;
+    u32 frames512_1023;
+    u32 frames1024_MaxSize;
+    u32 macRxError;
+    u32 droppedFrames;
+    u32 outMulticastFrames;
+    u32 outBroadcastFrames;
+    u32 undersizeFrames;
+} mib_counters_t;
+
+
+struct gt64240_private {
+    gt64240_rd_t* rx_ring;
+    gt64240_td_t* tx_ring;
+    // The Rx and Tx rings must be 16-byte aligned
+    dma_addr_t rx_ring_dma;
+    dma_addr_t tx_ring_dma;
+    char* hash_table;
+    // The Hash Table must be 8-byte aligned
+    dma_addr_t hash_table_dma;
+    int hash_mode;
+    
+    // The Rx buffers must be 8-byte aligned
+    char* rx_buff;
+    dma_addr_t rx_buff_dma;
+    // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+    // of payload must be 8-byte aligned
+    struct sk_buff* tx_skbuff[TX_RING_SIZE];
+    int rx_next_out;	/* The next free ring entry to receive */
+    int tx_next_in;	/* The next free ring entry to send */
+    int tx_next_out;	/* The last ring entry the ISR processed */
+    int tx_count;       /* current # of pkts waiting to be sent in Tx ring */
+    int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
+    int tx_full;        /* Tx ring is full */
+    
+    mib_counters_t mib;
+    struct net_device_stats stats;
+
+    int io_size;
+    int port_num;  // 0 or 1
+    int chip_rev;
+    u32 port_offset;
+    
+    int phy_addr; // PHY address
+    u32 last_psr; // last value of the port status register
+
+    int options;           /* User-settable misc. driver options. */
+    int drv_flags;
+    spinlock_t lock;	   /* Serialise access to device */
+    struct mii_if_info mii_if;
+};
+
+#endif /* _GT64240ETH_H */
diff -urN linux-2.4.23-bk1/drivers/net/gt96100eth.c linux-2.4.23-bk2/drivers/net/gt96100eth.c
--- linux-2.4.23-bk1/drivers/net/gt96100eth.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/gt96100eth.c	2003-12-03 02:49:52.000000000 -0800
@@ -700,7 +700,8 @@
 	struct net_device *dev = NULL;
     
 	if (gtif->irq < 0) {
-		printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_);
+		printk(KERN_ERR "%s: irq unknown - probing not supported\n",
+		       __FUNCTION__);
 		return -ENODEV;
 	}
     
@@ -1363,7 +1364,8 @@
 			gp->tx_full = 0;
 			if (gp->last_psr & psrLink) {
 				netif_wake_queue(dev);
-				dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_);
+				dbg(2, "%s: Tx Ring was full, queue waked\n",
+				    __FUNCTION__);
 			}
 		}
 	
@@ -1444,7 +1446,7 @@
 				if ((psr & psrLink) && !gp->tx_full &&
 				    netif_queue_stopped(dev)) {
 					dbg(0, ": Link up, waking queue.\n",
-					    __FUNCTION_);
+					    __FUNCTION__);
 					netif_wake_queue(dev);
 				} else if (!(psr & psrLink) &&
 					   !netif_queue_stopped(dev)) {
diff -urN linux-2.4.23-bk1/drivers/net/ioc3-eth.c linux-2.4.23-bk2/drivers/net/ioc3-eth.c
--- linux-2.4.23-bk1/drivers/net/ioc3-eth.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.23-bk2/drivers/net/ioc3-eth.c	2003-12-03 02:49:52.000000000 -0800
@@ -377,82 +377,6 @@
 		ip->dev->dev_addr[i - 2] = nic[i];
 }
 
-#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2)
-/*
- * Get the ether-address on SN1 nodes
- */
-static void ioc3_get_eaddr_sn(struct ioc3_private *ip)
-{
-	int ibrick_mac_addr_get(nasid_t, char *);
-	struct ioc3 *ioc3 = ip->regs;
-	nasid_t nasid_of_ioc3;
-	char io7eaddr[20];
-	long mac;
-	int err_val;
-
-	/*
-	 * err_val = ibrick_mac_addr_get(get_nasid(), io7eaddr );
-	 * 
-	 * BAD!!  The above call uses get_nasid() and assumes that
-	 * the ioc3 pointed to by struct ioc3 is hooked up to the
-	 * cbrick that we're running on.  The proper way to make this call
-	 * is to figure out which nasid the ioc3 is connected to
-	 * and use that to call ibrick_mac_addr_get.  Below is
-	 * a hack to do just that.
-	 */
-
-	/*
-	 * Get the nasid of the ioc3 from the ioc3's base addr.
-	 * FIXME: the 8 at the end assumes we're in memory mode, 
-	 * not node mode (for that, we'd change it to a 9).
-	 * Is there a call to extract this info from a physical
-	 * addr somewhere in an sn header file already?  If so,
-	 * we should probably use that, or restructure this routine
-	 * to use pci_dev and generic numa nodeid getting stuff.
-	 */
-	nasid_of_ioc3 = (((unsigned long)ioc3 >> 33) & ~(-1 << 8));
-	err_val = ibrick_mac_addr_get(nasid_of_ioc3, io7eaddr );
-
-
-	if (err_val) {
-		/* Couldn't read the eeprom; try OSLoadOptions. */
-		printk("WARNING: ibrick_mac_addr_get failed: %d\n", err_val);
-
-		/* this is where we hardwire the mac address
- 		 * 1st ibrick had 08:00:69:11:34:75
- 		 * 2nd ibrick had 08:00:69:11:35:35
- 		 *
- 		 * Eagan Machines:
- 		 *      mankato1 08:00:69:11:BE:95
- 		 *      warroad  08:00:69:11:bd:60
- 		 *      duron    08:00:69:11:34:60
- 		 *
- 		 * an easy way to get the mac address is to hook
- 		 * up an ip35, then from L1 do 'cti serial'
- 		 * and then look for MAC line XXX THIS DOESN"T QUITE WORK!!
- 		 */
-		printk("ioc3_get_eaddr: setting ethernet address to:\n -----> ");
-		ip->dev->dev_addr[0] = 0x8;
-		ip->dev->dev_addr[1] = 0x0;
-		ip->dev->dev_addr[2] = 0x69;
-		ip->dev->dev_addr[3] = 0x11;
-		ip->dev->dev_addr[4] = 0x34;
-		ip->dev->dev_addr[5] = 0x60;
-	}
-	else {
-		long simple_strtol(const char *,char **,unsigned int);
-
-		mac = simple_strtol(io7eaddr, (char **)0, 16);
-		ip->dev->dev_addr[0] = (mac >> 40) & 0xff;
-		ip->dev->dev_addr[1] = (mac >> 32) & 0xff;
-		ip->dev->dev_addr[2] = (mac >> 24) & 0xff;
-		ip->dev->dev_addr[3] = (mac >> 16) & 0xff;
-		ip->dev->dev_addr[4] = (mac >> 8) & 0xff;
-		ip->dev->dev_addr[5] = mac & 0xff;
-	}
-}
-#endif
-
 /*
  * Ok, this is hosed by design.  It's necessary to know what machine the
  * NIC is in in order to know how to read the NIC address.  We also have
@@ -460,30 +384,15 @@
  */
 static void ioc3_get_eaddr(struct ioc3_private *ip)
 {
-	void (*do_get_eaddr)(struct ioc3_private *ip) = NULL;
 	int i;
 
-	/*
-	 * We should also use this code for PCI cards, no matter what host
-	 * machine but how to know that we're a PCI card?
-	 */
-#ifdef CONFIG_SGI_IP27
-	do_get_eaddr = ioc3_get_eaddr_nic;
-#endif
-#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2)
-	do_get_eaddr = ioc3_get_eaddr_sn;
-#endif
 
-	if (!do_get_eaddr) {
-		printk(KERN_ERR "Don't know how to read MAC address of this "
-		       "IOC3 NIC\n");
-		return;
-	}
+	ioc3_get_eaddr_nic(ip);
 
 	printk("Ethernet address is ");
 	for (i = 0; i < 6; i++) {
 		printk("%02x", ip->dev->dev_addr[i]);
-		if (i < 7)
+		if (i < 5)
 			printk(":");
 	}
 	printk(".\n");
@@ -588,7 +497,7 @@
 			ip->stats.rx_frame_errors++;
 next:
 		ip->rx_skbs[n_entry] = new_skb;
-		rxr[n_entry] = cpu_to_be32((0xa5UL << 56) |
+		rxr[n_entry] = cpu_to_be64((0xa5UL << 56) |
 		                         ((unsigned long) rxb & TO_PHYS_MASK));
 		rxb->w0 = 0;				/* Clear valid flag */
 		n_entry = (n_entry + 1) & 511;		/* Update erpir */
@@ -1610,6 +1519,7 @@
 	struct ioc3_private *ip = dev->priv;
 	struct ioc3 *ioc3 = ip->regs;
 
+	unregister_netdev(dev);
 	iounmap(ioc3);
 	pci_release_regions(pdev);
 	kfree(dev);
@@ -1622,10 +1532,10 @@
 MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl);
 
 static struct pci_driver ioc3_driver = {
-	name:		"ioc3-eth",
-	id_table:	ioc3_pci_tbl,
-	probe:		ioc3_probe,
-	remove:		__devexit_p(ioc3_remove_one),
+	.name		= "ioc3-eth",
+	.id_table	= ioc3_pci_tbl,
+	.probe		= ioc3_probe,
+	.remove		= __devexit_p(ioc3_remove_one),
 };
 
 static int __init ioc3_init_module(void)
diff -urN linux-2.4.23-bk1/drivers/net/irda/au1k_ir.c linux-2.4.23-bk2/drivers/net/irda/au1k_ir.c
--- linux-2.4.23-bk1/drivers/net/irda/au1k_ir.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.23-bk2/drivers/net/irda/au1k_ir.c	2003-12-03 02:49:52.000000000 -0800
@@ -46,7 +46,13 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/au1000.h>
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
 #include <asm/pb1000.h>
+#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+#include <asm/db1x00.h>
+#else 
+#error au1k_ir: unsupported board
+#endif
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -71,10 +77,16 @@
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
 static struct net_device *ir_devs[NUM_IR_IFF];
 static char version[] __devinitdata =
-    "au1k_ircc:1.0 ppopov@mvista.com\n";
+    "au1k_ircc:1.2 ppopov@mvista.com\n";
 
 #define RUN_AT(x) (jiffies + (x))
 
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+static BCSR * const bcsr = (BCSR *)0xAE000000;
+#endif
+
+static spinlock_t ir_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * IrDA peripheral bug. You have to read the register
  * twice to get the right value.
@@ -126,7 +138,7 @@
 	if (ret != NULL) {
 		memset(ret, 0, size);
 		*dma_handle = virt_to_bus(ret);
-		ret = KSEG0ADDR(ret);
+		ret = (void *)KSEG0ADDR(ret);
 	}
 	return ret;
 }
@@ -134,7 +146,7 @@
 
 static void dma_free(void *vaddr, size_t size)
 {
-	vaddr = KSEG0ADDR(vaddr);
+	vaddr = (void *)KSEG0ADDR(vaddr);
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
@@ -211,7 +223,7 @@
 	struct au1k_private *aup = NULL;
 	int i, retval = 0, err;
 	db_dest_t *pDB, *pDBfree;
-	unsigned long temp;
+	dma_addr_t temp;
 
 	dev->priv = kmalloc(sizeof(struct au1k_private), GFP_KERNEL);
 	if (dev->priv == NULL) {
@@ -292,6 +304,14 @@
 		aup->tx_ring[i]->flags = 0;
 		aup->tx_db_inuse[i] = pDB;
 	}
+
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+	/* power on */
+	bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
+	bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL;
+	au_sync();
+#endif
+
 	return 0;
 
 out:
@@ -532,13 +552,13 @@
 	flags = ptxd->flags;
 
 	if (flags & AU_OWN) {
-		printk(KERN_INFO "%s: tx_full\n", dev->name);
+		printk(KERN_DEBUG "%s: tx_full\n", dev->name);
 		netif_stop_queue(dev);
 		aup->tx_full = 1;
 		return 1;
 	}
 	else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {
-		printk(KERN_INFO "%s: tx_full\n", dev->name);
+		printk(KERN_DEBUG "%s: tx_full\n", dev->name);
 		netif_stop_queue(dev);
 		aup->tx_full = 1;
 		return 1;
@@ -558,6 +578,7 @@
 		memcpy((void *)pDB->vaddr, skb->data, skb->len);
 		ptxd->count_0 = skb->len & 0xff;
 		ptxd->count_1 = (skb->len >> 8) & 0xff;
+
 	}
 	else {
 		/* SIR */
@@ -565,6 +586,7 @@
 		ptxd->count_0 = len & 0xff;
 		ptxd->count_1 = (len >> 8) & 0xff;
 		ptxd->flags |= IR_DIS_CRC;
+		au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c);
 	}
 	ptxd->flags |= AU_OWN;
 	au_sync();
@@ -699,12 +721,14 @@
 	u32 control;
 	int ret = 0, timeout = 10, i;
 	volatile ring_dest_t *ptxd;
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+	unsigned long irda_resets;
+#endif
 
 	if (speed == aup->speed)
 		return ret;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&ir_lock, flags);
 
 	/* disable PHY first */
 	writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE);
@@ -745,10 +769,20 @@
 		ptxd->flags = AU_OWN;
 	}
 
-	if (speed == 4000000)
+	if (speed == 4000000) {
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+		bcsr->resets |= BCSR_RESETS_FIR_SEL;
+#else /* Pb1000 and Pb1100 */
 		writel(1<<13, CPLD_AUX1);
-	else
+#endif
+	}
+	else {
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+		bcsr->resets &= ~BCSR_RESETS_FIR_SEL;
+#else /* Pb1000 and Pb1100 */
 		writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
+#endif
+	}
 
 	switch (speed) {
 	case 9600:	
@@ -794,18 +828,18 @@
 	}
 	else {
 		if (control & (1<<11))
-			printk(KERN_INFO "%s Valid SIR config\n", dev->name);
+			printk(KERN_DEBUG "%s Valid SIR config\n", dev->name);
 		if (control & (1<<12))
-			printk(KERN_INFO "%s Valid MIR config\n", dev->name);
+			printk(KERN_DEBUG "%s Valid MIR config\n", dev->name);
 		if (control & (1<<13))
-			printk(KERN_INFO "%s Valid FIR config\n", dev->name);
+			printk(KERN_DEBUG "%s Valid FIR config\n", dev->name);
 		if (control & (1<<10))
-			printk(KERN_INFO "%s TX enabled\n", dev->name);
+			printk(KERN_DEBUG "%s TX enabled\n", dev->name);
 		if (control & (1<<9))
-			printk(KERN_INFO "%s RX enabled\n", dev->name);
+			printk(KERN_DEBUG "%s RX enabled\n", dev->name);
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&ir_lock, flags);
 	return ret;
 }
 
diff -urN linux-2.4.23-bk1/drivers/net/meth.c linux-2.4.23-bk2/drivers/net/meth.c
--- linux-2.4.23-bk1/drivers/net/meth.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/meth.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,863 +0,0 @@
-/*
- * meth.c -- O2 Builtin 10/100 Ethernet driver
- *
- * Copyright (C) 2001 Ilya Volynets
- *
- *	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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/errno.h>  /* error codes */
-#include <linux/types.h>  /* size_t */
-#include <linux/interrupt.h> /* mark_bh */
-#include <linux/pci.h>
-
-#include <linux/in.h>
-#include <linux/netdevice.h>   /* struct device, and other headers */
-#include <linux/etherdevice.h> /* eth_type_trans */
-#include <linux/ip.h>          /* struct iphdr */
-#include <linux/tcp.h>         /* struct tcphdr */
-#include <linux/skbuff.h>
-#include <linux/mii.h> /*MII definitions */
-
-#include <asm/ip32/crime.h>
-#include <asm/ip32/mace.h>
-#include <asm/ip32/ip32_ints.h>
-
-#include "meth.h"
-
-#include <linux/in6.h>
-#include <asm/checksum.h>
-
-#ifndef MFE_DEBUG
-#define MFE_DEBUG 0
-#endif
-
-#if MFE_DEBUG>=1
-#define DPRINTK(str,args...) printk (KERN_DEBUG "meth(%ld): %s: " str, jiffies, __FUNCTION__ , ## args)
-#define MFE_RX_DEBUG 2
-#else
-#define DPRINTK(str,args...)
-#define MFE_RX_DEBUG 0
-#endif
-
-
-static const char *version="meth.c: Ilya Volynets (ilya@theIlya.com)";
-static const char *meth_str="SGI O2 Fast Ethernet";
-MODULE_AUTHOR("Ilya Volynets");
-MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver");
-
-/* This is a load-time options */
-/*static int eth = 0;
-MODULE_PARM(eth, "i");*/
-
-#define HAVE_TX_TIMEOUT
-/* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
-#define TX_TIMEOUT (400*HZ/1000)
-
-#ifdef HAVE_TX_TIMEOUT
-static int timeout = TX_TIMEOUT;
-MODULE_PARM(timeout, "i");
-#endif
-
-int meth_eth;
-
-
-/*
- * This structure is private to each device. It is used to pass
- * packets in and out, so there is place for a packet
- */
-
-typedef struct meth_private {
-    struct net_device_stats stats;
-	volatile struct meth_regs *regs;
-	u64 mode; /* in-memory copy of MAC control register */
-	int  phy_addr; /* address of phy, used by mdio_* functions, initialized in mdio_probe*/
-	tx_packet *tx_ring;
-	dma_addr_t tx_ring_dma;
-	int free_space;
-	struct sk_buff *tx_skbs[TX_RING_ENTRIES];
-	dma_addr_t      tx_skb_dmas[TX_RING_ENTRIES];
-	int tx_read,tx_write;
-	int tx_count;
-
-	rx_packet *rx_ring[RX_RING_ENTRIES];
-	dma_addr_t rx_ring_dmas[RX_RING_ENTRIES];
-	int rx_write;
-
-    spinlock_t meth_lock;
-} meth_private;
-
-extern struct net_device meth_devs[];
-void meth_tx_timeout (struct net_device *dev);
-void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
-        
-/* global, initialized in ip32-setup.c */
-char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
-
-static inline void load_eaddr(struct net_device *dev,
-			      volatile struct meth_regs *regs)
-{
-	int i;
-	DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-		(int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
-		(int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
-	//memcpy(dev->dev_addr,o2meth_eaddr+2,6);
-	for (i=0; i<6; i++)
-		dev->dev_addr[i]=o2meth_eaddr[i];
-	regs->mac_addr= //dev->dev_addr[0]|(dev->dev_addr[1]<<8)|
-					//dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)|
-					//dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40);
-	(*(u64*)o2meth_eaddr)>>16;
-	DPRINTK("MAC, finally is %0lx\n",regs->mac_addr);
-}
-
-/*
- *Waits for BUSY status of mdio bus to clear
- */
-#define WAIT_FOR_PHY(___regs, ___rval)			\
-	while((___rval=___regs->phy_data)&MDIO_BUSY){	\
-		udelay(25);								\
-	}
-/*read phy register, return value read */
-static int mdio_read(meth_private *priv,int phyreg)
-{
-	volatile meth_regs* regs=priv->regs;
-	volatile u32 rval;
-	WAIT_FOR_PHY(regs,rval)
-	regs->phy_registers=(priv->phy_addr<<5)|(phyreg&0x1f);
-	udelay(25);
-	regs->phy_trans_go=1;
-	udelay(25);
-	WAIT_FOR_PHY(regs,rval)
-	return rval&MDIO_DATA_MASK;
-}
-
-/*write phy register */
-static void mdio_write(meth_private* priv,int pfyreg,int val)
-{
-	volatile meth_regs* regs=priv->regs;
-	int rval;
-///	DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg);
-	spin_lock_irq(&priv->meth_lock);
-	WAIT_FOR_PHY(regs,rval)
-	regs->phy_registers=(priv->phy_addr<<5)|(pfyreg&0x1f);
-	regs->phy_data=val;
-	udelay(25);
-	WAIT_FOR_PHY(regs,rval)
-	spin_unlock_irq(&priv->meth_lock);
-}
-
-/* Modify phy register using given mask and value */
-static void mdio_update(meth_private* priv,int phyreg, int val, int mask)
-{
-	int rval;
-	DPRINTK("RMW value %i to PHY register %i with mask %i\n",val,phyreg,mask);
-	rval=mdio_read(priv,phyreg);
-	rval=(rval&~mask)|(val&mask);
-	mdio_write(priv,phyreg,rval);
-}
-
-/* handle errata data on MDIO bus */
-//static void mdio_errata(meth_private *priv)
-//{
-	/* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */
-//}
-static int mdio_probe(meth_private *priv)
-{
-	int i, p2, p3;
-	DPRINTK("Detecting PHY kind\n");
-	/* check if phy is detected already */
-	if(priv->phy_addr>=0&&priv->phy_addr<32)
-		return 0;
-	spin_lock_irq(&priv->meth_lock);
-	for (i=0;i<32;++i){
-		priv->phy_addr=(char)i;
-		p2=mdio_read(priv,2);
-#ifdef MFE_DEBUG
-		p3=mdio_read(priv,3);
-		switch ((p2<<12)|(p3>>4)){
-			case PHY_QS6612X:
-				DPRINTK("PHY is QS6612X\n");
-				break;
-			case PHY_ICS1889:
-				DPRINTK("PHY is ICS1889\n");
-				break;
-			case PHY_ICS1890:
-				DPRINTK("PHY is ICS1890\n");
-				break;
-			case PHY_DP83840:
-				DPRINTK("PHY is DP83840\n");
-				break;
-		}
-#endif
-		if(p2!=0xffff&&p2!=0x0000){
-			DPRINTK("PHY code: %x\n",(p2<<12)|(p3>>4));
-			break;
-		}
-	}
-	spin_unlock_irq(&priv->meth_lock);
-	if(priv->phy_addr<32) {
-		return 0;
-	}
-	DPRINTK("Oopsie! PHY is not known!\n");
-	priv->phy_addr=-1;
-	return -ENODEV;
-}
-
-static void meth_check_link(struct net_device *dev)
-{
-	struct meth_private *priv = (struct meth_private *) dev->priv;
-	int mii_partner = mdio_read(priv, 5);
-	int mii_advertising = mdio_read(priv, 4);
-	int negotiated = mii_advertising & mii_partner;
-	int duplex, speed;
-
-	if (mii_partner == 0xffff)
-		return;
-
-	duplex = ((negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040)?METH_PHY_FDX:0;
-	speed = (negotiated & 0x0380)?METH_100MBIT:0;
-
-	if ((priv->mode & METH_PHY_FDX) ^ duplex)
-	{
-		DPRINTK("Setting %s-duplex\n", duplex ? "full" : "half");
-		if (duplex)
-			priv->mode |= METH_PHY_FDX;
-		else
-			priv->mode &= ~METH_PHY_FDX;
-		priv->regs->mac_ctrl = priv->mode;
-	}
-
-	if ((priv->mode & METH_100MBIT) ^ speed)
-	{
-		DPRINTK("Setting %dMbs mode\n", speed ? 100 : 10);
-		if (duplex)
-			priv->mode |= METH_100MBIT;
-		else
-			priv->mode &= ~METH_100MBIT;
-		priv->regs->mac_ctrl = priv->mode;
-	}
-}
-
-
-static int meth_init_tx_ring(meth_private *priv)
-{
-	/* Init TX ring */
-	DPRINTK("Initializing TX ring\n");
-	priv->tx_ring = (tx_packet *) pci_alloc_consistent(NULL,TX_RING_BUFFER_SIZE,&(priv->tx_ring_dma));
-	if(!priv->tx_ring)
-		return -ENOMEM;
-	memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE);
-	priv->tx_count = priv->tx_read = priv->tx_write = 0;
-	priv->regs->tx_ring_base = priv->tx_ring_dma;
-	priv->free_space = TX_RING_ENTRIES;
-	/* Now init skb save area */
-	memset(priv->tx_skbs,0,sizeof(priv->tx_skbs));
-	memset(priv->tx_skb_dmas,0,sizeof(priv->tx_skb_dmas));
-	DPRINTK("Done with TX ring init\n");
-	return 0;
-}
-
-static int meth_init_rx_ring(meth_private *priv)
-{
-	int i;
-	DPRINTK("Initializing RX ring\n");
-	for(i=0;i<RX_RING_ENTRIES;i++){
-		DPRINTK("\t1:\t%i\t",i);
-		/*if(!(priv->rx_ring[i]=get_free_page(GFP_KERNEL)))
-			return -ENOMEM;
-		DPRINTK("\t2:\t%i\n",i);*/
-		priv->rx_ring[i]=(rx_packet*)pci_alloc_consistent(NULL,METH_RX_BUFF_SIZE,&(priv->rx_ring_dmas[i]));
-		/* I'll need to re-sync it after each RX */
-		DPRINTK("\t%p\n",priv->rx_ring[i]);
-		priv->regs->rx_fifo=priv->rx_ring_dmas[i];
-	}
-	priv->rx_write = 0;
-	DPRINTK("Done with RX ring\n");
-	return 0;
-}
-static void meth_free_tx_ring(meth_private *priv)
-{
-	int i;
-
-	/* Remove any pending skb */
-	for (i = 0; i < TX_RING_ENTRIES; i++) {
-	  if (priv->tx_skbs[i])
-		dev_kfree_skb(priv->tx_skbs[i]);
-		priv->tx_skbs[i] = NULL;
-	}
-	pci_free_consistent(NULL,
-			    TX_RING_BUFFER_SIZE,
-			    priv->tx_ring,
-			    priv->tx_ring_dma);
-}
-static void meth_free_rx_ring(meth_private *priv)
-{
-	int i;
-
-	for(i=0;i<RX_RING_ENTRIES;i++)
-		pci_free_consistent(NULL,
-				    METH_RX_BUFF_SIZE,
-				    priv->rx_ring[i],
-				    priv->rx_ring_dmas[i]);
-}
-
-int meth_reset(struct net_device *dev)
-{
-	struct meth_private *priv = (struct meth_private *) dev->priv;
-
-	/* Reset card */
-	priv->regs->mac_ctrl = SGI_MAC_RESET;
-	priv->regs->mac_ctrl = 0;
-	udelay(25);
-	DPRINTK("MAC control after reset: %016lx\n", priv->regs->mac_ctrl);
-
-	/* Load ethernet address */
-	load_eaddr(dev, priv->regs);
-	/* Should load some "errata", but later */
-	
-	/* Check for device */
-	if(mdio_probe(priv) < 0) {
-		DPRINTK("Unable to find PHY\n");
-		return -ENODEV;
-	}
-
-	/* Initial mode -- 10|Half-duplex|Accept normal packets */
-	priv->mode=METH_ACCEPT_MCAST|METH_DEFAULT_IPG;
-	if(dev->flags | IFF_PROMISC)
-		priv->mode |= METH_PROMISC;
-	priv->regs->mac_ctrl = priv->mode;
-
-	/* Autonegociate speed and duplex mode */
-	meth_check_link(dev);
-
-	/* Now set dma control, but don't enable DMA, yet */
-	priv->regs->dma_ctrl= (4 << METH_RX_OFFSET_SHIFT) |
-		              (RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT);
-
-	return(0);
-}
-
-/*============End Helper Routines=====================*/
-
-/*
- * Open and close
- */
-
-int meth_open(struct net_device *dev)
-{
-	meth_private *priv=dev->priv;
-	volatile meth_regs *regs=priv->regs;
-
-	MOD_INC_USE_COUNT;
-
-	/* Start DMA */
-	regs->dma_ctrl|=
-	        METH_DMA_TX_EN|/*METH_DMA_TX_INT_EN|*/
-		METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
-
-	if(request_irq(dev->irq,meth_interrupt,SA_SHIRQ,meth_str,dev)){
-		printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-	netif_start_queue(dev);
-	DPRINTK("Opened... DMA control=0x%08lx\n", regs->dma_ctrl);
-	return 0;
-}
-
-int meth_release(struct net_device *dev)
-{
-    netif_stop_queue(dev); /* can't transmit any more */
-	/* shut down dma */
-	((meth_private*)(dev->priv))->regs->dma_ctrl&=
-		~(METH_DMA_TX_EN|METH_DMA_TX_INT_EN|
-		METH_DMA_RX_EN|METH_DMA_RX_INT_EN);
-	free_irq(dev->irq, dev);
-    MOD_DEC_USE_COUNT;
-    return 0;
-}
-
-/*
- * Configuration changes (passed on by ifconfig)
- */
-int meth_config(struct net_device *dev, struct ifmap *map)
-{
-    if (dev->flags & IFF_UP) /* can't act on a running interface */
-        return -EBUSY;
-
-    /* Don't allow changing the I/O address */
-    if (map->base_addr != dev->base_addr) {
-        printk(KERN_WARNING "meth: Can't change I/O address\n");
-        return -EOPNOTSUPP;
-    }
-
-    /* Allow changing the IRQ */
-    if (map->irq != dev->irq) {
-        printk(KERN_WARNING "meth: Can't change IRQ\n");
-        return -EOPNOTSUPP;
-    }
-	DPRINTK("Configured\n");
-
-    /* ignore other fields */
-    return 0;
-}
-
-/*
- * Receive a packet: retrieve, encapsulate and pass over to upper levels
- */
-void meth_rx(struct net_device* dev)
-{
-    struct sk_buff *skb;
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-	rx_packet *rxb;
-	DPRINTK("RX...\n");
-	// TEMP	while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
-	while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
-	        int len=rxb->status.parsed.rx_len - 4; /* omit CRC */
-		DPRINTK("(%i)\n",priv->rx_write);
-		/* length sanity check */
-		if(len < 60 || len > 1518) {
-		  printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x.\n",
-			 dev->name, priv->rx_write, rxb->status.raw);
-		  priv->stats.rx_errors++;
-		  priv->stats.rx_length_errors++;
-		}
-		if(!(rxb->status.raw&METH_RX_STATUS_ERRORS)){
-			skb=alloc_skb(len+2,GFP_ATOMIC);/* Should be atomic -- we are in interrupt */
-			if(!skb){
-				/* Ouch! No memory! Drop packet on the floor */
-				DPRINTK("!!!>>>Ouch! Not enough Memory for RX buffer!\n");
-				priv->stats.rx_dropped++;
-			} else {
-				skb_reserve(skb, 2); /* align IP on 16B boundary */  
-    			memcpy(skb_put(skb, len), rxb->buf, len);
-			    /* Write metadata, and then pass to the receive level */
-			    skb->dev = dev;
-			    skb->protocol = eth_type_trans(skb, dev);
-				//skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
-			   
-				DPRINTK("passing packet\n");
-				DPRINTK("len = %d rxb->status = %x\n",
-					len, rxb->status.raw);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				priv->stats.rx_packets++;
-				priv->stats.rx_bytes+=len;
-				DPRINTK("There we go... Whew...\n");
-			}
-		}
-		priv->regs->rx_fifo=priv->rx_ring_dmas[priv->rx_write];
-		rxb->status.raw=0;		
-		priv->rx_write=(priv->rx_write+1)&(RX_RING_ENTRIES-1);
-	}
-}
-
-static int meth_tx_full(struct net_device *dev)
-{
-	struct meth_private *priv = (struct meth_private *) dev->priv;
-
-	return(priv->tx_count >= TX_RING_ENTRIES-1);
-}
-
-void meth_tx_cleanup(struct net_device* dev, int rptr)
-{
-	meth_private *priv=dev->priv;
-	tx_packet* status;
-	struct sk_buff *skb;
-
-	spin_lock(&priv->meth_lock);
-
-	/* Stop DMA */
-	priv->regs->dma_ctrl &= ~(METH_DMA_TX_INT_EN);
-
-	while(priv->tx_read != rptr){
-		skb = priv->tx_skbs[priv->tx_read];
-		status = &priv->tx_ring[priv->tx_read];
-		if(!status->header.res.sent)
-			break;
-		if(status->header.raw & METH_TX_STATUS_DONE) {
-			priv->stats.tx_packets++;
-			priv->stats.tx_bytes += skb->len;
-		}
-		dev_kfree_skb_irq(skb);
-		priv->tx_skbs[priv->tx_read] = NULL;
-		status->header.raw = 0;
-		priv->tx_read = (priv->tx_read+1)&(TX_RING_ENTRIES-1);
-		priv->tx_count --;
-	}
-
-	/* wake up queue if it was stopped */
-	if (netif_queue_stopped(dev) && ! meth_tx_full(dev)) {
-		netif_wake_queue(dev);
-	}
-
-	spin_unlock(priv->meth_lock);
-}
-
-/*
- * The typical interrupt entry point
- */
-void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
-{
-	struct meth_private *priv;
-	union {
-		u32	reg; /*Whole status register */
-		struct {
-			u32			:	2,
-				rx_seq	:	5,
-				tx_read	:	9,
-				
-				rx_read	:	8,
-				int_mask:	8;
-		} parsed;
-	} status;
-	/*
-	 * As usual, check the "device" pointer for shared handlers.
-	 * Then assign "struct device *dev"
-	 */
-	struct net_device *dev = (struct net_device *)dev_id;
-	/* ... and check with hw if it's really ours */
-
-	if (!dev /*paranoid*/ ) return;
-
-	/* Lock the device */
-	priv = (struct meth_private *) dev->priv;
-
-	status.reg = priv->regs->int_flags;
-    
-	DPRINTK("Interrupt, status %08x...\n",status.reg);
-	if (status.parsed.int_mask & METH_INT_RX_THRESHOLD) {
-		/* send it to meth_rx for handling */
-		meth_rx(dev);
-	}
-
-	if (status.parsed.int_mask & (METH_INT_TX_EMPTY|METH_INT_TX_PKT)) {
-		/* a transmission is over: free the skb */
-		meth_tx_cleanup(dev, status.parsed.tx_read);
-	}
-	/* check for errors too... */
-	if (status.parsed.int_mask & (METH_INT_TX_LINK_FAIL))
-		printk(KERN_WARNING "meth: link failure\n");
-	if (status.parsed.int_mask & (METH_INT_MEM_ERROR))
-		printk(KERN_WARNING "meth: memory error\n");
-	if (status.parsed.int_mask & (METH_INT_TX_ABORT))
-		printk(KERN_WARNING "meth: aborted\n");
-	DPRINTK("Interrupt handling done...\n");
-	
-	priv->regs->int_flags=status.reg&0xff; /* clear interrupts */
-}
-
-/*
- * Transmits packets that fit into TX descriptor (are <=120B)
- */
-static void meth_tx_short_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	int len = (skb->len<ETH_ZLEN)?ETH_ZLEN:skb->len;
-
-	DPRINTK("preparing short packet\n");
-	/* maybe I should set whole thing to 0 first... */
-	memcpy(desc->data.dt+(120-len),skb->data,skb->len);
-	if(skb->len < len)
-		memset(desc->data.dt+120-len+skb->len,0,len-skb->len);
-	desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16);
-	DPRINTK("desc=%016lx\n",desc->header.raw);
-}
-#define TX_CATBUF1 BIT(25)
-static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	void *buffer_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL));
-	int unaligned_len = (int)((u64)buffer_data - (u64)skb->data);
-	int buffer_len = skb->len - unaligned_len;
-	dma_addr_t catbuf;
-
-	DPRINTK("preparing 1 page...\n");
-	DPRINTK("length=%d data=%p\n", skb->len, skb->data);
-	DPRINTK("unaligned_len=%d\n", unaligned_len);
-	DPRINTK("buffer_data=%p buffer_len=%d\n",
-	       buffer_data,
-	       buffer_len);
-
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1);
-
-	/* unaligned part */
-	if(unaligned_len){
-		memcpy(desc->data.dt+(120-unaligned_len),
-		       skb->data, unaligned_len);
-		desc->header.raw |= (128-unaligned_len) << 16;
-	}
-
-	/* first page */
-	catbuf = pci_map_single(NULL,
-				buffer_data,
-				buffer_len,
-				PCI_DMA_TODEVICE);
-	DPRINTK("catbuf=%x\n", catbuf);
-	desc->data.cat_buf[0].form.start_addr = catbuf >> 3;
-	desc->data.cat_buf[0].form.len = buffer_len-1;
-	DPRINTK("desc=%016lx\n",desc->header.raw);
-	DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw);
-}
-#define TX_CATBUF2 BIT(26)
-static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	void *buffer1_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL));
-	void *buffer2_data = (void *)PAGE_ALIGN((u64)skb->data);
-	int unaligned_len = (int)((u64)buffer1_data - (u64)skb->data);
-	int buffer1_len = (int)((u64)buffer2_data - (u64)buffer1_data);
-	int buffer2_len = skb->len - buffer1_len - unaligned_len;
-	dma_addr_t catbuf1, catbuf2;
-
-	DPRINTK("preparing 2 pages... \n");
-	DPRINTK("length=%d data=%p\n", skb->len, skb->data);
-	DPRINTK("unaligned_len=%d\n", unaligned_len);
-	DPRINTK("buffer1_data=%p buffer1_len=%d\n",
-	       buffer1_data,
-	       buffer1_len);
-	DPRINTK("buffer2_data=%p buffer2_len=%d\n",
-	       buffer2_data,
-	       buffer2_len);
-
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1);
-	/* unaligned part */
-	if(unaligned_len){
-		memcpy(desc->data.dt+(120-unaligned_len),
-		       skb->data, unaligned_len);
-		desc->header.raw |= (128-unaligned_len) << 16;
-	}
-
-	/* first page */
-	catbuf1 = pci_map_single(NULL,
-				 buffer1_data,
-				 buffer1_len,
-				 PCI_DMA_TODEVICE);
-	DPRINTK("catbuf1=%x\n", catbuf1);
-	desc->data.cat_buf[0].form.start_addr = catbuf1 >> 3;
-	desc->data.cat_buf[0].form.len = buffer1_len-1;
-	/* second page */
-	catbuf2 = pci_map_single(NULL,
-				 buffer2_data,
-				 buffer2_len,
-				 PCI_DMA_TODEVICE);
-	DPRINTK("catbuf2=%x\n", catbuf2);
-	desc->data.cat_buf[1].form.start_addr = catbuf2 >> 3;
-	desc->data.cat_buf[1].form.len = buffer2_len-1;
-	DPRINTK("desc=%016lx\n",desc->header.raw);
-	DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw);
-	DPRINTK("cat_buf[1].raw=%016lx\n",desc->data.cat_buf[1].raw);
-}
-
-
-void meth_add_to_tx_ring(meth_private *priv, struct sk_buff* skb)
-{
-	DPRINTK("Transmitting data...\n");
-	if(skb->len <= 120) {
-		/* Whole packet fits into descriptor */
-		meth_tx_short_prepare(priv,skb);
-	} else if(PAGE_ALIGN((u64)skb->data) !=
-		  PAGE_ALIGN((u64)skb->data+skb->len-1)) {
-		/* Packet crosses page boundary */
-		meth_tx_2page_prepare(priv,skb);
-	} else {
-		/* Packet is in one page */
-		meth_tx_1page_prepare(priv,skb);
-	}
-
-	/* Remember the skb, so we can free it at interrupt time */
-	priv->tx_skbs[priv->tx_write] = skb;
-	priv->tx_write = (priv->tx_write+1) & (TX_RING_ENTRIES-1);
-	priv->regs->tx_info.wptr = priv->tx_write;
-	priv->tx_count ++;
-	/* Enable DMA transfer */
-	priv->regs->dma_ctrl |= METH_DMA_TX_INT_EN;
-}
-
-/*
- * Transmit a packet (called by the kernel)
- */
-int meth_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	struct meth_private *priv = (struct meth_private *) dev->priv;
-
-	spin_lock_irq(&priv->meth_lock);
-
-	meth_add_to_tx_ring(priv, skb);
-	dev->trans_start = jiffies; /* save the timestamp */
-
-	/* If TX ring is full, tell the upper layer to stop sending packets */
-	if (meth_tx_full(dev)) {
-	        DPRINTK("TX full: stopping\n");
-		netif_stop_queue(dev);
-	}
-
-	spin_unlock_irq(&priv->meth_lock);
-
-	return 0;
-}
-
-/*
- * Deal with a transmit timeout.
- */
-
-void meth_tx_timeout (struct net_device *dev)
-{
-	struct meth_private *priv = (struct meth_private *) dev->priv;
-	
-	printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
-
-	/* Protect against concurrent rx interrupts */
-	spin_lock_irq(&priv->meth_lock);
-
-	/* Try to reset the adaptor. */
-	meth_reset(dev);
-
-	priv->stats.tx_errors++;
-
-	/* Clear all rings */
-	meth_free_tx_ring(priv);
-	meth_free_rx_ring(priv);
-	meth_init_tx_ring(priv);
-	meth_init_rx_ring(priv);
-
-	/* Restart dma */
-	priv->regs->dma_ctrl|=METH_DMA_TX_EN|METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
-
-	/* Enable interrupt */
-	spin_unlock_irq(&priv->meth_lock);
-
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-
-	return;
-}
-
-/*
- * Ioctl commands 
- */
-int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- 
-    DPRINTK("ioctl\n");
-    return 0;
-}
-
-/*
- * Return statistics to the caller
- */
-struct net_device_stats *meth_stats(struct net_device *dev)
-{
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-    return &priv->stats;
-}
-
-/*
- * The init function (sometimes called probe).
- * It is invoked by register_netdev()
- */
-int meth_init(struct net_device *dev)
-{
-	meth_private *priv;
-	int ret;
-	/* 
-	 * Then, assign other fields in dev, using ether_setup() and some
-	 * hand assignments
-	 */
-	ether_setup(dev); /* assign some of the fields */
-
-	dev->open            = meth_open;
-	dev->stop            = meth_release;
-	dev->set_config      = meth_config;
-	dev->hard_start_xmit = meth_tx;
-	dev->do_ioctl        = meth_ioctl;
-	dev->get_stats       = meth_stats;
-#ifdef HAVE_TX_TIMEOUT
-	dev->tx_timeout      = meth_tx_timeout;
-	dev->watchdog_timeo  = timeout;
-#endif
-	dev->irq		 = MACE_ETHERNET_IRQ;
-	SET_MODULE_OWNER(dev);
-
-	/*
-	 * Then, allocate the priv field. This encloses the statistics
-	 * and a few private fields.
-	 */
-	priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL);
-	if (priv == NULL)
-		return -ENOMEM;
-	dev->priv=priv;
-	memset(priv, 0, sizeof(struct meth_private));
-	spin_lock_init(&((struct meth_private *) dev->priv)->meth_lock);
-	/*
-	 * Make the usual checks: check_region(), probe irq, ...  -ENODEV
-	 * should be returned if no device found.  No resource should be
-	 * grabbed: this is done on open(). 
-	 */
-	priv->regs=(meth_regs*)SGI_MFE;
-	dev->base_addr=SGI_MFE;
-	priv->phy_addr = -1; /* No phy is known yet... */
-
-	/* Initialize the hardware */
-	if((ret=meth_reset(dev)) < 0)
-	        return ret;
-
-	/* Allocate the ring buffers */
-	if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){
-		meth_free_tx_ring(priv);
-		meth_free_rx_ring(priv);
-		return ret;
-	}
-
-	printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29);
-
-    return 0;
-}
-
-/*
- * The devices
- */
-
-struct net_device meth_devs[1] = {
-    { init: meth_init, }  /* init, nothing more */
-};
-
-/*
- * Finally, the module stuff
- */
-
-int meth_init_module(void)
-{
-	int result, device_present = 0;
-
-	strcpy(meth_devs[0].name, "eth%d");
-
-	if ( (result = register_netdev(meth_devs)) )
-		printk("meth: error %i registering device \"%s\"\n",
-		       result, meth_devs->name);
-	else device_present++;
-#ifndef METH_DEBUG
-	EXPORT_NO_SYMBOLS;
-#endif
-	
-	return device_present ? 0 : -ENODEV;
-}
-
-void meth_cleanup(void)
-{
-    kfree(meth_devs->priv);
-    unregister_netdev(meth_devs);
-    return;
-}
-
-module_init(meth_init_module);
-module_exit(meth_cleanup);
diff -urN linux-2.4.23-bk1/drivers/net/meth.h linux-2.4.23-bk2/drivers/net/meth.h
--- linux-2.4.23-bk1/drivers/net/meth.h	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/meth.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,273 +0,0 @@
-
-/*
- * snull.h -- definitions for the network module
- *
- * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
- * Copyright (C) 2001 O'Reilly & Associates
- *
- * The source code in this file can be freely used, adapted,
- * and redistributed in source or binary form, so long as an
- * acknowledgment appears in derived source files.  The citation
- * should list that the code comes from the book "Linux Device
- * Drivers" by Alessandro Rubini and Jonathan Corbet, published
- * by O'Reilly & Associates.   No warranty is attached;
- * we cannot take responsibility for errors or fitness for use.
- */
-
-/* version dependencies have been confined to a separate file */
-
-#define SGI_MFE		(MACE_BASE+MACE_ENET)
-/*		(0xBF280000)*/
-
-/* Tunable parameters */
-#define TX_RING_ENTRIES 64	/* 64-512?*/
-
-#define RX_RING_ENTRIES 16 /* Do not change */
-/* Internal constants */
-#define TX_RING_BUFFER_SIZE	(TX_RING_ENTRIES*sizeof(tx_packet))
-#define RX_BUFFER_SIZE 1546 /* ethenet packet size */
-#define METH_RX_BUFF_SIZE 4096
-#define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2) /* staus vector + 2 bytes of padding */
-#define RX_BUCKET_SIZE 256
-
-
-
-/* For more detailed explanations of what each field menas,
-   see Nick's great comments to #defines below (or docs, if
-   you are lucky enough toget hold of them :)*/
-
-/* tx status vector is written over tx command header upon
-   dma completion. */
-
-typedef struct tx_status_vector {
-	u64		sent:1; /* always set to 1...*/
-	u64		pad0:34;/* always set to 0 */
-	u64		flags:9;			/*I'm too lazy to specify each one separately at the moment*/
-	u64		col_retry_cnt:4;	/*collision retry count*/
-	u64		len:16;				/*Transmit length in bytes*/
-} tx_status_vector;
-
-/*
- * Each packet is 128 bytes long.
- * It consists of header, 0-3 concatination
- * buffer pointers and up to 120 data bytes.
- */
-typedef struct tx_packet_hdr {
-	u64		pad1:36; /*should be filled with 0 */
-	u64		cat_ptr3_valid:1,	/*Concatination pointer valid flags*/
-			cat_ptr2_valid:1,
-			cat_ptr1_valid:1;
-	u64		tx_int_flag:1;		/*Generate TX intrrupt when packet has been sent*/
-	u64		term_dma_flag:1;	/*Terminate transmit DMA on transmit abort conditions*/
-	u64		data_offset:7;		/*Starting byte offset in ring data block*/
-	u64		data_len:16;		/*Length of valid data in bytes-1*/
-} tx_packet_hdr;
-typedef union tx_cat_ptr {
-	struct {
-		u64		pad2:16; /* should be 0 */
-		u64		len:16;				/*length of buffer data - 1*/
-		u64		start_addr:29;		/*Physical starting address*/
-		u64		pad1:3; /* should be zero */
-	} form;
-	u64 raw;
-} tx_cat_ptr;
-
-typedef struct tx_packet {
-	union {
-		tx_packet_hdr header;
-		tx_status_vector res;
-		u64 raw;
-	}header;
-	union {
-		tx_cat_ptr cat_buf[3];
-		char dt[120];
-	} data;
-} tx_packet;
-
-typedef union rx_status_vector {
-	struct {
-		u64		pad1:1;/*fill it with ones*/
-		u64		pad2:15;/*fill with 0*/
-		u64		ip_chk_sum:16;
-		u64		seq_num:5;
-		u64		mac_addr_match:1;
-		u64		mcast_addr_match:1;
-		u64		carrier_event_seen:1;
-		u64		bad_packet:1;
-		u64		long_event_seen:1;
-		u64		invalid_preamble:1;
-		u64		broadcast:1;
-		u64		multicast:1;
-		u64		crc_error:1;
-		u64		huh:1;/*???*/
-		u64		rx_code_violation:1;
-		u64		rx_len:16;
-	} parsed;
-	u64 raw;
-} rx_status_vector;
-
-typedef struct rx_packet {
-	rx_status_vector status;
-        u64 pad[3]; /* For whatever reason, there needs to be 4 double-word offset */
-        u16 pad2;
-	char buf[METH_RX_BUFF_SIZE-sizeof(rx_status_vector)-3*sizeof(u64)-sizeof(u16)];/* data */
-} rx_packet;
-
-typedef struct meth_regs {
-	u64		mac_ctrl;		/*0x00,rw,31:0*/
-	u64		int_flags;		/*0x08,rw,30:0*/
-	u64		dma_ctrl;		/*0x10,rw,15:0*/
-	u64		timer;			/*0x18,rw,5:0*/
-	u64		int_tx;			/*0x20,wo,0:0*/
-	u64		int_rx;			/*0x28,wo,9:4*/
-	struct {
-		u32 tx_info_pad;
-		u32 rptr:16,wptr:16;
-	}		tx_info;		/*0x30,rw,31:0*/
-	u64		tx_info_al;		/*0x38,rw,31:0*/
-	struct {
-		u32	rx_buff_pad1;
-		u32	rx_buff_pad2:8,
-			wptr:8,
-			rptr:8,
-			depth:8;
-	}		rx_buff;		/*0x40,ro,23:0*/
-	u64		rx_buff_al1;	/*0x48,ro,23:0*/
-	u64		rx_buff_al2;	/*0x50,ro,23:0*/
-	u64		int_update;		/*0x58,wo,31:0*/
-	u32		phy_data_pad;
-	u32		phy_data;		/*0x60,rw,16:0*/
-	u32		phy_reg_pad;
-	u32		phy_registers;	/*0x68,rw,9:0*/
-	u64		phy_trans_go;	/*0x70,wo,0:0*/
-	u64		backoff_seed;	/*0x78,wo,10:0*/
-	u64		imq_reserved[4];/*0x80,ro,64:0(x4)*/
-	/*===================================*/
-	u64		mac_addr;		/*0xA0,rw,47:0, I think it's MAC address, but I'm not sure*/
-	u64		mcast_addr;		/*0xA8,rw,47:0, This seems like secondary MAC address*/
-	u64		mcast_filter;	/*0xB0,rw,63:0*/
-	u64		tx_ring_base;	/*0xB8,rw,31:13*/
-	/* Following are read-only debugging info register */
-	u64		tx_pkt1_hdr;	/*0xC0,ro,63:0*/
-	u64		tx_pkt1_ptr[3];	/*0xC8,ro,63:0(x3)*/
-	u64		tx_pkt2_hdr;	/*0xE0,ro,63:0*/
-	u64		tx_pkt2_ptr[3];	/*0xE8,ro,63:0(x3)*/
-	/*===================================*/
-	u32		rx_pad;
-	u32		rx_fifo;
-	u64		reserved[31];
-}meth_regs;
-
-	/* Bits in METH_MAC */
-
-#define SGI_MAC_RESET		BIT(0)	/* 0: MAC110 active in run mode, 1: Global reset signal to MAC110 core is active */
-#define METH_PHY_FDX		BIT(1) /* 0: Disable full duplex, 1: Enable full duplex */
-#define METH_PHY_LOOP	BIT(2) /* 0: Normal operation, follows 10/100mbit and M10T/MII select, 1: loops internal MII bus */
-				       /*    selects ignored */
-#define METH_100MBIT		BIT(3) /* 0: 10meg mode, 1: 100meg mode */
-#define METH_PHY_MII		BIT(4) /* 0: MII selected, 1: SIA selected */
-				       /*   Note: when loopback is set this bit becomes collision control.  Setting this bit will */
-				       /*         cause a collision to be reported. */
-
-				       /* Bits 5 and 6 are used to determine the the Destination address filter mode */
-#define METH_ACCEPT_MY 0			/* 00: Accept PHY address only */
-#define METH_ACCEPT_MCAST 0x20	/* 01: Accept physical, broadcast, and multicast filter matches only */
-#define METH_ACCEPT_AMCAST 0x40	/* 10: Accept physical, broadcast, and all multicast packets */
-#define METH_PROMISC 0x60		/* 11: Promiscious mode */
-
-#define METH_PHY_LINK_FAIL	BIT(7) /* 0: Link failure detection disabled, 1: Hardware scans for link failure in PHY */
-
-#define METH_MAC_IPG	0x1ffff00
-
-#define METH_DEFAULT_IPG ((17<<15) | (11<<22) | (21<<8))
-						/* 0x172e5c00 */ /* 23, 23, 23 */ /*0x54A9500 *//*21,21,21*/
-				       /* Bits 8 through 14 are used to determine Inter-Packet Gap between "Back to Back" packets */
-				       /* The gap depends on the clock speed of the link, 80ns per increment for 100baseT, 800ns  */
-				       /* per increment for 10BaseT */
-
-				       /* Bits 15 through 21 are used to determine IPGR1 */
-
-				       /* Bits 22 through 28 are used to determine IPGR2 */
-
-#define METH_REV_SHIFT 29       /* Bits 29 through 31 are used to determine the revision */
-				       /* 000: Inital revision */
-				       /* 001: First revision, Improved TX concatenation */
-
-
-/* DMA control bits */
-#define METH_RX_OFFSET_SHIFT 12 /* Bits 12:14 of DMA control register indicate starting offset of packet data for RX operation */
-#define METH_RX_DEPTH_SHIFT 4 /* Bits 8:4 define RX fifo depth -- when # of RX fifo entries != depth, interrupt is generted */
-
-#define METH_DMA_TX_EN BIT(1) /* enable TX DMA */
-#define METH_DMA_TX_INT_EN BIT(0) /* enable TX Buffer Empty interrupt */
-#define METH_DMA_RX_EN BIT(15) /* Enable RX */
-#define METH_DMA_RX_INT_EN BIT(9) /* Enable interrupt on RX packet */
-
-
-/* RX status bits */
-
-#define METH_RX_ST_RCV_CODE_VIOLATION BIT(16)
-#define METH_RX_ST_DRBL_NBL BIT(17)
-#define METH_RX_ST_CRC_ERR BIT(18)
-#define METH_RX_ST_MCAST_PKT BIT(19)
-#define METH_RX_ST_BCAST_PKT BIT(20)
-#define METH_RX_ST_INV_PREAMBLE_CTX BIT(21)
-#define METH_RX_ST_LONG_EVT_SEEN BIT(22)
-#define METH_RX_ST_BAD_PACKET BIT(23)
-#define METH_RX_ST_CARRIER_EVT_SEEN BIT(24)
-#define METH_RX_ST_MCAST_FILTER_MATCH BIT(25)
-#define METH_RX_ST_PHYS_ADDR_MATCH BIT(26)
-
-#define METH_RX_STATUS_ERRORS \
-	( \
-	METH_RX_ST_RCV_CODE_VIOLATION| \
-	METH_RX_ST_CRC_ERR| \
-	METH_RX_ST_INV_PREAMBLE_CTX| \
-	METH_RX_ST_LONG_EVT_SEEN| \
-	METH_RX_ST_BAD_PACKET| \
-	METH_RX_ST_CARRIER_EVT_SEEN \
-	)
-	/* Bits in METH_INT */
-	/* Write _1_ to corresponding bit to clear */
-#define METH_INT_TX_EMPTY	BIT(0)	/* 0: No interrupt pending, 1: The TX ring buffer is empty */
-#define METH_INT_TX_PKT		BIT(1)	/* 0: No interrupt pending */
-					      	/* 1: A TX message had the INT request bit set, the packet has been sent. */
-#define METH_INT_TX_LINK_FAIL	BIT(2)	/* 0: No interrupt pending, 1: PHY has reported a link failure */
-#define METH_INT_MEM_ERROR	BIT(3)	/* 0: No interrupt pending */
-						/* 1: A memory error occurred durring DMA, DMA stopped, Fatal */
-#define METH_INT_TX_ABORT		BIT(4)	/* 0: No interrupt pending, 1: The TX aborted operation, DMA stopped, FATAL */
-#define METH_INT_RX_THRESHOLD	BIT(5)	/* 0: No interrupt pending, 1: Selected receive threshold condition Valid */
-#define METH_INT_RX_UNDERFLOW	BIT(6)	/* 0: No interrupt pending, 1: FIFO was empty, packet could not be queued */
-#define METH_INT_RX_OVERFLOW		BIT(7)	/* 0: No interrupt pending, 1: DMA FIFO Overflow, DMA stopped, FATAL */
-
-#define METH_INT_RX_RPTR_MASK 0x0001F00		/* Bits 8 through 12 alias of RX read-pointer */
-
-						/* Bits 13 through 15 are always 0. */
-
-#define METH_INT_TX_RPTR_MASK 0x1FF0000	        /* Bits 16 through 24 alias of TX read-pointer */
-
-#define METH_INT_SEQ_MASK    0x2E000000	        /* Bits 25 through 29 are the starting seq number for the message at the */
-						/* top of the queue */
-
-#define METH_ERRORS ( \
-	METH_INT_RX_OVERFLOW|	\
-	METH_INT_RX_UNDERFLOW|	\
-	METH_INT_MEM_ERROR|			\
-	METH_INT_TX_ABORT)
-
-#define METH_INT_MCAST_HASH		BIT(30) /* If RX DMA is enabled the hash select logic output is latched here */
-
-/* TX status bits */
-#define METH_TX_STATUS_DONE BIT(23) /* Packet was transmitted successfully */
-
-/* Tx command header bits */
-#define METH_TX_CMD_INT_EN BIT(24) /* Generate TX interrupt when packet is sent */
-
-/* Phy MDIO interface busy flag */
-#define MDIO_BUSY    BIT(16)
-#define MDIO_DATA_MASK 0xFFFF
-/* PHY defines */
-#define PHY_QS6612X    0x0181441    /* Quality TX */
-#define PHY_ICS1889    0x0015F41    /* ICS FX */
-#define PHY_ICS1890    0x0015F42    /* ICS TX */
-#define PHY_DP83840    0x20005C0    /* National TX */
diff -urN linux-2.4.23-bk1/drivers/net/mv64340_eth.c linux-2.4.23-bk2/drivers/net/mv64340_eth.c
--- linux-2.4.23-bk1/drivers/net/mv64340_eth.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/mv64340_eth.c	2003-12-03 02:49:52.000000000 -0800
@@ -5,6 +5,9 @@
  * Based on the 64360 driver from:
  * Copyright (C) 2002 rabeeh@galileo.co.il
  *
+ * Copyright (C) 2003 PMC-Sierra, Inc.,
+ *      written by Manish Lachwani (lachwani@pmc-sierra.com)
+ *
  * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
  *
  * This program is free software; you can redistribute it and/or
@@ -20,7 +23,6 @@
  * 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 <linux/config.h>
 #include <linux/version.h>
@@ -39,10 +41,10 @@
 #include <linux/init.h>
 #include <linux/in.h>
 #include <linux/pci.h>
-
+#include <asm/smp.h>
+#include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
 #include <net/ip.h>
 
 #include <asm/bitops.h>
@@ -50,12 +52,6 @@
 #include <asm/types.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-
-#ifdef CONFIG_NET_FASTROUTE
-#include <linux/if_arp.h>
-#include <net/ip.h>
-#endif
-
 #include "mv64340_eth.h"
 
 /*************************************************************************
@@ -87,13 +83,24 @@
 static int mv64340_eth_change_mtu(struct net_device *, int);
 static struct net_device_stats *mv64340_eth_get_stats(struct net_device *);
 static void eth_port_init_mac_tables(ETH_PORT eth_port_num);
+#ifdef MV64340_NAPI
+static int mv64340_poll(struct net_device *dev, int *budget);
+#endif
 
-static unsigned char prom_mac_addr_base[6];
+unsigned char prom_mac_addr_base[6];
+unsigned long mv64340_sram_base;
 
 /************************************************** 
  * Helper functions - used inside the driver only *
  **************************************************/
 
+static inline void __netif_rx_complete(struct net_device *dev)
+{
+        if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
+        list_del(&dev->poll_list);
+        clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
 static void *mv64340_eth_malloc_ring(unsigned int size)
 {
 	dma_addr_t dma_handle;
@@ -152,7 +159,6 @@
 	spin_unlock_irqrestore(&port_private->lock, flags);
 	return 0;
 }
-
 /**********************************************************************
  * mv64340_eth_rx_task
  *								       
@@ -181,8 +187,10 @@
 	
 	while (port_private->rx_ring_skbs < (port_private->rx_ring_size - 5)) {
 		/* The +8 for buffer allignment and another 32 byte extra */
+
 		skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES);
 		if (!skb)
+			/* Better luck next time */
 			break;
 		port_private->rx_ring_skbs++;
 		pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;
@@ -226,7 +234,6 @@
 #endif
 }
 
-
 /**********************************************************************
  * mv64340_eth_rx_task_timer_wrapper
  *								       
@@ -302,37 +309,6 @@
 
 
 /**********************************************************************
- * mv64340_eth_accept_fastpath
- *								       
- * Used to authenticate to the kernel that a fast path entry can be
- * added to device's routing table cache
- *
- * Input : pointer to ethernet interface network device structure and
- *         a pointer to the designated entry to be added to the cache.
- * Output : zero upon success, negative upon failure
- **********************************************************************/
-#ifdef CONFIG_NET_FASTROUTE
-static int mv64340_eth_accept_fastpath(struct net_device *dev,
-				       struct dst_entry *dst)
-{
-	struct net_device *odev = dst->dev;
-
-	if (dst->ops->protocol != __constant_htons(ETH_P_IP)) {
-		return -1;
-	}
-
-	if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL) {
-		return -1;
-	}
-
-	printk(KERN_INFO
-	       "Accepted fastpath (destination interface %s)\n", odev->name);
-	return 0;
-}
-#endif
-
-
-/**********************************************************************
  * mv64340_eth_set_mac_address
  *								       
  * Change the interface's mac address.
@@ -364,7 +340,27 @@
  **********************************************************************/
 static void mv64340_eth_tx_timeout(struct net_device *dev)
 {
-	printk(KERN_INFO "%s: TX timeout\n", dev->name);
+	ETH_PORT_INFO *ethernet_private = dev->priv;
+	printk(KERN_INFO "%s: TX timeout  ", dev->name);
+	printk(KERN_INFO "Resetting card \n");
+
+	/* Do the reset outside of interrupt context */
+        schedule_task(&ethernet_private->tx_timeout_task);
+}
+
+/**********************************************************************
+ * mv64340_eth_tx_timeout_task
+ *
+ * Actual routine to reset the adapter when a timeout on Tx has occurred
+ **********************************************************************/
+static void mv64340_eth_tx_timeout_task(struct net_device *dev)
+{
+        ETH_PORT_INFO *ethernet_private = dev->priv;
+
+        netif_device_detach(dev);
+        eth_port_reset(ethernet_private->port_num);
+        eth_port_start(ethernet_private);
+        netif_device_attach(dev);
 }
 
 /**********************************************************************
@@ -410,7 +406,18 @@
 				dev_kfree_skb_irq((struct sk_buff *)
 						  pkt_info.return_info);
 				released = 0;
+				if (skb_shinfo(pkt_info.return_info)->nr_frags)
+					pci_unmap_page(0, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						PCI_DMA_TODEVICE);
+
+				if (port_private->tx_ring_skbs != 1)
+					port_private->tx_ring_skbs--;
 			}
+			else 
+				pci_unmap_page(0, pkt_info.buf_ptr,
+						pkt_info.byte_cnt,
+						PCI_DMA_TODEVICE);
 
 			/* 
 			 * Decrement the number of outstanding skbs counter on the
@@ -419,7 +426,6 @@
 			if (port_private->tx_ring_skbs == 0)
 				panic
 				    ("ERROR - TX outstanding SKBs counter is corrupted\n");
-			port_private->tx_ring_skbs--;
 
 		}
 
@@ -438,8 +444,12 @@
  *
  * Output : number of served packets
  **********************************************************************/
-
+#ifdef MV64340_NAPI
+static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max,
+								int budget)
+#else
 static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max)
+#endif
 {
 	ETH_PORT_INFO *ethernet_private;
 	struct mv64340_eth_priv *port_private;
@@ -449,33 +459,29 @@
 	unsigned int received_packets = 0;
 	struct net_device_stats *stats;
 
-#ifdef CONFIG_NET_FASTROUTE
-	register int fast_routed = 0;
-	struct ethhdr *eth;
-	struct iphdr *iph;
-	unsigned h, CPU_ID = smp_processor_id();
-	struct rtable *rt;
-	struct net_device *odev;
-#endif
-
 	ethernet_private = dev->priv;
 	port_private =
 	    (struct mv64340_eth_priv *) ethernet_private->port_private;
 	port_num = port_private->port_num;
 	stats = &port_private->stats;
 
+#ifdef MV64340_NAPI
+	while ((eth_port_receive(ethernet_private, &pkt_info) == ETH_OK) 
+		&&
+		budget > 0) {
+#else
 	while ((--max)
 	       && (eth_port_receive(ethernet_private, &pkt_info) ==
 		   ETH_OK)) {
+#endif
 		port_private->rx_ring_skbs--;
 		received_packets++;
-
+#ifdef MV64340_NAPI
+		budget--;
+#endif
 		/* Update statistics. Note byte count includes 4 byte CRC count */
 		stats->rx_packets++;
 		stats->rx_bytes += pkt_info.byte_cnt;
-#ifdef CONFIG_NET_FASTROUTE
-		fast_routed = 0;
-#endif
 		skb = (struct sk_buff *) pkt_info.return_info;
 		/*
 		 * In case received a packet without first / last bits on OR the error
@@ -502,111 +508,34 @@
 			}
 			dev_kfree_skb_irq(skb);
 		} else {
-			/* The -4 is for the CRC in the trailer of the received packet */
+			struct ethhdr *eth_h;
+			struct iphdr *ip_h;
+
+			/*
+			 * The -4 is for the CRC in the trailer of the
+			 * received packet
+			 */
 			skb_put(skb, pkt_info.byte_cnt - 4);
 			skb->dev = dev;
-#ifdef CONFIG_NET_FASTROUTE
-			eth = (struct ethhdr *) skb->data;
-			if (eth->h_proto == __constant_htons(ETH_P_IP)) {
-				iph =
-				    (struct iphdr *) (skb->data +
-						      ETH_HLEN);
-				h =
-				    (*(u8 *) & iph->daddr ^ *(u8 *) & iph->
-				     saddr) & NETDEV_FASTROUTE_HMASK;
-				rt = (struct rtable *) (dev->fastpath[h]);
-				if (rt != NULL &&
-				    ((u16 *) & iph->daddr)[0] ==
-				    ((u16 *) & rt->key.dst)[0]
-				    && ((u16 *) & iph->daddr)[1] ==
-				    ((u16 *) & rt->key.dst)[1]
-				    && ((u16 *) & iph->saddr)[0] ==
-				    ((u16 *) & rt->key.src)[0]
-				    && ((u16 *) & iph->saddr)[1] ==
-				    ((u16 *) & rt->key.src)[1]
-				    && !rt->u.dst.obsolete) {
-					odev = rt->u.dst.dev;
-					netdev_rx_stat
-					    [CPU_ID].fastroute_hit++;
-					if (*(u8 *) iph == 0x45
-					    && (!(eth->h_dest[0] & 0x80))
-					    && neigh_is_valid(rt->u.dst.
-							      neighbour)
-					    && iph->ttl > 1) {
-						/* Fast Route Path */
-						fast_routed = 1;
-						if (
-						    (!netif_queue_stopped
-						     (odev))
-						    &&
-						    (!spin_is_locked
-						     (odev->xmit_lock))
-						    && (skb->len <=
-							(odev->mtu +
-							 ETH_HLEN + 2 +
-							 4))) {
-							skb->pkt_type =
-							    PACKET_FASTROUTE;
-							skb->protocol =
-							    __constant_htons
-							    (ETH_P_IP);
-							ip_decrease_ttl
-							    (iph);
-							memcpy
-							    (eth->h_source,
-							     odev->
-							     dev_addr, 6);
-							memcpy(eth->h_dest,
-							       rt->u.dst.
-							       neighbour->
-							       ha, 6);
-							skb->dev = odev;
-							if
-							    (odev->
-							    hard_start_xmit
-						      (skb, odev) != 0) {
-								panic
-								    ("%s: FastRoute path corrupted",
-								     dev->
-								     name);
-							}
-							netdev_rx_stat
-							    [CPU_ID].
-							    fastroute_success++;
-						}
-						/* Semi Fast Route Path */
-						else {
-							skb->pkt_type =
-							    PACKET_FASTROUTE;
-							skb->nh.raw =
-							    skb->data +
-							    ETH_HLEN;
-							skb->protocol =
-							    __constant_htons
-							    (ETH_P_IP);
-							netdev_rx_stat
-							    [CPU_ID].
-							    fastroute_defer++;
-							netif_rx(skb);
-						}
-					}
-				}
+
+			eth_h = (struct ethhdr *) skb->data;
+			ip_h = (struct iphdr *) (skb->data + ETH_HLEN);
+			if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+				skb->csum = htons((pkt_info.cmd_sts
+							& 0x0007fff8) >> 3);
 			}
-			if (fast_routed == 0)
-#endif
-			{
-				struct ethhdr *eth_h;
-				struct iphdr *ip_h;
-				eth_h = (struct ethhdr *) skb->data;
-				ip_h =
-				    (struct iphdr *) (skb->data +
-						      ETH_HLEN);
+			else 
 				skb->ip_summed = CHECKSUM_NONE;
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-			}
+			skb->protocol = eth_type_trans(skb, dev);
+#ifdef MV64340_NAPI
+			netif_receive_skb(skb);
+#else
+			netif_rx(skb);
+#endif
 		}
 	}
+
 	return received_packets;
 }
 
@@ -635,67 +564,52 @@
 
 	/* Read interrupt cause registers */
 	eth_int_cause =
-	    MV_READ_DATA(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num));
-	if (eth_int_cause & BIT1)
+	    (MV_READ_DATA(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) & 
+			INT_CAUSE_UNMASK_ALL);
+
+	if (eth_int_cause & BIT1) 
 		eth_int_cause_ext =
-		    MV_READ_DATA(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG
-				 (port_num));
+		    (MV_READ_DATA(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
+				INT_CAUSE_UNMASK_ALL_EXT);
 	else
 		eth_int_cause_ext = 0;
 
-	/* Mask with shadowed mask registers */
-#ifdef MV64340_RX_QUEUE_FILL_ON_TASK
-	eth_int_cause &= INT_CAUSE_CHECK_BITS;
-	eth_int_cause_ext &= INT_CAUSE_CHECK_BITS_EXT;
-#else
-	eth_int_cause &= INT_CAUSE_UNMASK_ALL;
-	eth_int_cause_ext &= INT_CAUSE_UNMASK_ALL_EXT;
+#ifdef MV64340_NAPI
+	if (!(eth_int_cause & 0x0007fffd)) {
+	/* Dont ack the Rx interrupt */
 #endif
-
-	/*
-	 * If no real interrupt occured, exit.
-	 * This can happen when using gigE interrupt coalescing mechanism.
-	 */
-	if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) {
-		return;
+		/*
+	 	 * Clear specific ethernet port intrerrupt registers by acknowleding
+	 	 * relevant bits.
+   	 	 */
+		MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),
+			 ~eth_int_cause);
+		if (eth_int_cause_ext != 0x0)
+			MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
+				 ~eth_int_cause_ext);
+
+		/* UDP change : We may need this */
+                 if (eth_int_cause_ext & 0x0000ffff) {
+                        if (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) {
+                                if (netif_queue_stopped(dev) &&
+				    (dev->flags & IFF_RUNNING) &&
+				    (MV64340_TX_QUEUE_SIZE > port_private->tx_ring_skbs + 1)) {
+                                         netif_wake_queue(dev);
+                                }
+                        }
+                 }
+#ifdef MV64340_NAPI
 	}
-
-	/*
-	 * Clear specific ethernet port intrerrupt registers by acknowleding
-	 * relevant bits.
-	 */
-	MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),
-		 ~eth_int_cause);
-	if (eth_int_cause_ext != 0x0)
-		MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
-			 ~eth_int_cause_ext);
-
-	if (eth_int_cause_ext & 0x0000ffff) {
-		/* 
-		 * Check if released more than one packet.
-		 * Otherwise don't wake up queue
-		 */
-		if (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) {
-			/*
-			 * If the interface was stopped before, and link is up,
-			 * wakeup TX queue. Note that this might be a problematic
-			 * issue since the multiple TX queues in the system controller,
-			 * and in which few queues are stucked.
-			 * If this is the case, then a TX packet to a stucked queue is
-			 * forwarded to another TX queue of the interface ; BUT in the
-			 * current implementation only one TX / RX queues are used.
-			 */
-			if (netif_queue_stopped(dev)
-			     && (dev->flags & IFF_RUNNING)
-			    &&
-			    (MV64340_TX_QUEUE_SIZE > port_private->tx_ring_skbs + 1)) {
-				netif_wake_queue(dev);
-			}
+	else {
+		if (netif_rx_schedule_prep(dev)) {
+			/* Mask all the interrupts */
+			MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0);
+			MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
+			__netif_rx_schedule(dev);
 		}
-	}
-	if (eth_int_cause & 0x0007fffd) {	/*RxBuffer returned, RxResource Error */
+#else
 		unsigned int total_received = 0;
-		/* Rx Return Buffer / Resource Error Priority queue 0 */
+		
 		if (eth_int_cause & (BIT2 | BIT11)) {
 			total_received +=
 			    mv64340_eth_receive_queue(dev, 0);
@@ -713,7 +627,7 @@
 #else
 		port_private->rx_task.routine(dev);
 #endif
-
+#endif
 	}
 	/* PHY status changed */
 	if (eth_int_cause_ext & (BIT16 | BIT20)) {
@@ -739,6 +653,15 @@
 			MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1);
 		}
 	}
+
+        /*
+         * If no real interrupt occured, exit.
+         * This can happen when using gigE interrupt coalescing mechanism.
+         */
+        if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) {
+                return;
+        }
+
 	return;
 }
 
@@ -800,6 +723,7 @@
 	unsigned int port_num;
 	u32 phy_reg_data;
 	unsigned int size;
+	int i;
 
 	ethernet_private = dev->priv;
 	port_private =
@@ -824,6 +748,7 @@
 
 	/* Set the MAC Address */
 	memcpy(ethernet_private->port_mac_addr, dev->dev_addr, 6);
+
 	eth_port_init(ethernet_private);
 
 	/* Set rx_task pointers */
@@ -846,7 +771,7 @@
 
 	/* Assumes allocated ring is 16 bytes alligned */
 	ethernet_private->p_tx_desc_area =
-	    (ETH_TX_DESC *) mv64340_eth_malloc_ring(size);
+	    (ETH_TX_DESC *) mv64340_sram_base;
 	if (!ethernet_private->p_tx_desc_area) {
 		printk(KERN_ERR
 		       "%s: Cannot allocate Tx Ring (size %d bytes)\n",
@@ -898,6 +823,22 @@
 
 	eth_port_start(ethernet_private);
 
+	/* Interrupt Coalescing */
+
+#ifdef MV64340_COAL
+	port_private->rx_int_coal =
+		eth_port_set_rx_coal (port_num, 133000000, MV64340_RX_COAL);
+#endif
+
+	port_private->tx_int_coal =
+		eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL);  
+
+	/* Increase the Rx side buffer size */
+
+	MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) |
+			(MV_READ_DATA (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num))
+					& 0xfff1ffff));
+
 	/* Check Link status on phy */
 	eth_port_read_smi_reg(port_num, 1, &phy_reg_data);
 	if (!(phy_reg_data & 0x20)) {
@@ -907,10 +848,10 @@
 		netif_start_queue(dev);
 		dev->flags |= (IFF_RUNNING);
 	}
+
 	return 0;
 }
 
-
 static void mv64340_eth_free_tx_rings(struct net_device *dev)
 {
 	ETH_PORT_INFO *ethernet_private;
@@ -1022,7 +963,6 @@
 	ETH_PORT_INFO *ethernet_private;
 	struct mv64340_eth_priv *port_private;
 	unsigned int port_num;
-
 	ethernet_private = dev->priv;
 	port_private =
 	    (struct mv64340_eth_priv *) ethernet_private->port_private;
@@ -1048,6 +988,92 @@
 	return 0;
 }
 
+#ifdef MV64340_NAPI
+static void mv64340_tx(struct net_device *dev)
+{
+	ETH_PORT_INFO *ethernet_private;
+        struct mv64340_eth_priv *port_private;
+        unsigned int port_num;
+        PKT_INFO pkt_info;
+
+	ethernet_private = dev->priv;
+	port_private =
+            (struct mv64340_eth_priv *) ethernet_private->port_private;
+
+	port_num = port_private->port_num;
+
+	while (eth_tx_return_desc(ethernet_private, &pkt_info) == ETH_OK) {
+		if (pkt_info.return_info) {
+			dev_kfree_skb_irq((struct sk_buff *)
+                                                  pkt_info.return_info);
+			if (skb_shinfo(pkt_info.return_info)->nr_frags) 
+                                 pci_unmap_page(0, pkt_info.buf_ptr,
+                                             pkt_info.byte_cnt,
+                                             PCI_DMA_TODEVICE);
+
+                         if (port_private->tx_ring_skbs != 1)
+                                  port_private->tx_ring_skbs--;
+                } else 
+                       pci_unmap_page(0, pkt_info.buf_ptr,
+                             pkt_info.byte_cnt,
+                             PCI_DMA_TODEVICE);
+	}
+
+	if (netif_queue_stopped(dev) &&
+		(dev->flags & IFF_RUNNING) &&
+                (MV64340_TX_QUEUE_SIZE > port_private->tx_ring_skbs + 1)) {
+                       netif_wake_queue(dev);
+	}
+}
+
+/**********************************************************************
+ * mv64340_poll
+ *
+ * This function is used in case of NAPI
+ ***********************************************************************/
+static int mv64340_poll(struct net_device *netdev, int *budget)
+{
+	ETH_PORT_INFO *ethernet_private = netdev->priv;
+	struct mv64340_eth_priv *port_private = 
+		(struct mv64340_eth_priv *) ethernet_private->port_private;
+	int	done = 1, orig_budget, work_done;
+	unsigned long	flags;
+	unsigned int	port_num = port_private->port_num;
+
+	spin_lock_irqsave(&port_private->lock, flags);
+
+#ifdef MV64340_TX_FAST_REFILL
+	if (++ethernet_private->tx_clean_threshold > 5) {
+		mv64340_tx(netdev);
+		ethernet_private->tx_clean_threshold = 0;
+	}
+#endif
+	if ((u32)(MV_READ_DATA(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))                                      != (u32)ethernet_private->rx_used_desc_q) {
+		orig_budget = *budget;
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+		work_done = mv64340_eth_receive_queue(netdev, 0, orig_budget);
+		port_private->rx_task.routine(netdev);
+		*budget -= work_done;
+		netdev->quota -= work_done;
+		if (work_done >= orig_budget)
+			done = 0;
+	}
+
+	if (done) {
+		__netif_rx_complete(netdev);
+		MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0);
+                MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0);
+		MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 
+						INT_CAUSE_UNMASK_ALL);
+		MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+				                 INT_CAUSE_UNMASK_ALL_EXT);
+	}
+
+	spin_unlock_irqrestore(&port_private->lock, flags);
+	return (done ? 0 : 1);
+}
+#endif
 
 /**********************************************************************
  * mv64340_eth_start_xmit
@@ -1103,19 +1129,91 @@
 	spin_lock_irqsave(&port_private->lock, flags);
 
 	/* Update packet info data structure -- DMA owned, first last */
-	pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
-	    ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+	if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) {
+#endif
+		pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+	    				ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
 
-	pkt_info.byte_cnt = skb->len;
-	pkt_info.buf_ptr = pci_map_single
-		    (0, skb->data, skb->len, PCI_DMA_TODEVICE);
-
-	pkt_info.return_info = skb;
-	status = eth_port_send(ethernet_private, &pkt_info);
-	if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
-		printk(KERN_ERR "%s: Error on transmitting packet\n",
-			       dev->name);
-	port_private->tx_ring_skbs++;
+		pkt_info.byte_cnt = skb->len;
+		pkt_info.buf_ptr = pci_map_single
+			    (0, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+		pkt_info.return_info = skb;
+		status = eth_port_send(ethernet_private, &pkt_info);
+		if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
+			printk(KERN_ERR "%s: Error on transmitting packet\n",
+				       dev->name);
+		port_private->tx_ring_skbs++;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+	} 
+	else {
+		unsigned int    frag;
+		u32		ipheader;
+
+                /* first frag which is skb header */
+                pkt_info.byte_cnt = skb_headlen(skb);
+                pkt_info.buf_ptr = pci_map_single(0, skb->data,
+                                        skb_headlen(skb), PCI_DMA_TODEVICE);
+                pkt_info.return_info = 0;
+                ipheader =   (skb->nh.iph->ihl << 11);
+                pkt_info.cmd_sts = ETH_TX_FIRST_DESC | 
+					ETH_GEN_TCP_UDP_CHECKSUM |
+					ETH_GEN_IP_V_4_CHECKSUM |
+                                        ipheader;
+		/* CPU already calculated pseudo header checksum. So, use it */
+                pkt_info.l4i_chk = skb->h.th->check;
+                status = eth_port_send(ethernet_private, &pkt_info);
+		if (status != ETH_OK) {
+	                if ((status == ETH_ERROR))
+        	                printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
+	                if (status == ETH_QUEUE_FULL)
+        	                printk("Error on Queue Full \n");
+                	if (status == ETH_QUEUE_LAST_RESOURCE)
+                        	printk("Tx resource error \n");
+		}
+
+                /* Check for the remaining frags */
+                for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+                        skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+                        pkt_info.l4i_chk = 0x0000;
+                        pkt_info.cmd_sts = 0x00000000;
+
+                        /* Last Frag enables interrupt and frees the skb */
+                        if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
+                                pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
+                                                        ETH_TX_LAST_DESC;
+                                pkt_info.return_info = skb;
+                                port_private->tx_ring_skbs++;
+                        }
+                        else {
+                                pkt_info.return_info = 0;
+                        }
+                        pkt_info.byte_cnt = this_frag->size;
+                        if (this_frag->size < 8)
+                                printk("%d : \n", skb_shinfo(skb)->nr_frags);
+
+                        pkt_info.buf_ptr = pci_map_page(0,
+                                        this_frag->page,
+                                        this_frag->page_offset,
+                                        this_frag->size,
+                                        PCI_DMA_TODEVICE);
+
+                        status = eth_port_send(ethernet_private, &pkt_info);
+
+			if (status != ETH_OK) {
+	                        if ((status == ETH_ERROR))
+        	                        printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
+
+       		                 if (status == ETH_QUEUE_LAST_RESOURCE)
+                	                printk("Tx resource error \n");
+
+                        	if (status == ETH_QUEUE_FULL)
+                                	printk("Queue is full \n");
+			}
+                }
+        }
+#endif
 
 	/* Check if TX queue can handle another skb. If not, then
 	 * signal higher layers to stop requesting TX
@@ -1138,7 +1236,6 @@
 	return 0;		/* success */
 }
 
-
 /**********************************************************************
  * mv64340_eth_get_stats
  *
@@ -1195,16 +1292,29 @@
 
 	/* No need to Tx Timeout */
 	dev->tx_timeout = mv64340_eth_tx_timeout;
+#ifdef MV64340_NAPI
+        dev->poll = mv64340_poll;
+        dev->weight = 64;
+#endif
+
 	dev->watchdog_timeo = 2 * HZ;
 	dev->tx_queue_len = MV64340_TX_QUEUE_SIZE;
 	dev->flags &= ~(IFF_RUNNING);
 	dev->base_addr = 0;
 	dev->change_mtu = &mv64340_eth_change_mtu;
-#ifdef CONFIG_NET_FASTROUTE
-	dev->accept_fastpath = mv64340_eth_accept_fastpath;
+
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+#ifdef MAX_SKB_FRAGS
+#ifndef CONFIG_JAGUAR_DMALOW
+        /*
+         * Zero copy can only work if we use Discovery II memory. Else, we will
+         * have to map the buffers to ISA memory which is only 16 MB
+         */
+        dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM;
+#endif
+#endif
 #endif
 	ethernet_private = dev->priv;
-
 	/* Allocate memory for stats data structure and spinlock etc... */
 	ethernet_private->port_private = (void *)
 	    kmalloc(sizeof(struct mv64340_eth_priv), GFP_KERNEL);
@@ -1223,7 +1333,6 @@
 	else {
 		printk(KERN_ERR "%s: Invalid port number\n", dev->name);
 		kfree(ethernet_private->port_private);
-
 		err = -ENODEV;
 		goto out_free_dev;
 	}
@@ -1234,6 +1343,10 @@
 
 	memset(&port_private->stats, 0, sizeof(struct net_device_stats));
 
+	/* Configure the timeout task */
+        INIT_TQUEUE(&ethernet_private->tx_timeout_task,
+                        (void (*)(void *))mv64340_eth_tx_timeout_task, dev);
+
 	/* Init spinlock */
 	spin_lock_init(&port_private->lock);
 
@@ -1250,6 +1363,19 @@
 		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
+	if (dev->features & NETIF_F_SG)
+		printk("Scatter Gather Enabled  ");
+
+	if (dev->features & NETIF_F_IP_CSUM)
+		printk("TX TCP/IP Checksumming Supported  \n");
+
+	printk("RX TCP/UDP Checksum Offload ON, \n");
+	printk("TX and RX Interrupt Coalescing ON \n");
+
+#ifdef MV64340_NAPI
+	printk("RX NAPI Enabled \n");
+#endif
+
 	return 0;
 
 out_free_dev:
@@ -1310,7 +1436,7 @@
 module_exit(mv64340_cleanup_module);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, and Matthew Dharm");
+MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani");
 MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340");
 
 /*************************************************************************
@@ -1480,33 +1606,6 @@
 #define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \
 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << (8 + rx_queue)))
 
-#if 0
-#define CURR_RFD_GET(p_curr_desc) \
- ((p_curr_desc) = p_eth_port_ctrl->p_rx_curr_desc_q)
-
-#define CURR_RFD_SET(p_curr_desc) \
- (p_eth_port_ctrl->p_rx_curr_desc_q = (p_curr_desc))
-
-#define USED_RFD_GET(p_used_desc) \
- ((p_used_desc) = p_eth_port_ctrl->p_rx_used_desc_q)
-
-#define USED_RFD_SET(p_used_desc)\
-(p_eth_port_ctrl->p_rx_used_desc_q = (p_used_desc))
-
-
-#define CURR_TFD_GET(p_curr_desc) \
- ((p_curr_desc) = p_eth_port_ctrl->p_tx_curr_desc_q)
-
-#define CURR_TFD_SET(p_curr_desc) \
- (p_eth_port_ctrl->p_tx_curr_desc_q = (p_curr_desc))
-
-#define USED_TFD_GET(p_used_desc) \
- ((p_used_desc) = p_eth_port_ctrl->p_tx_used_desc_q)
-
-#define USED_TFD_SET(p_used_desc) \
- (p_eth_port_ctrl->p_tx_used_desc_q = (p_used_desc))
-#endif
-
 #define LINK_UP_TIMEOUT		100000
 #define PHY_BUSY_TIMEOUT	10000000
 
@@ -1618,7 +1717,7 @@
 	/* Assignment of Tx CTRP of given queue */
 	tx_curr_desc = p_eth_port_ctrl->tx_curr_desc_q;
 	MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num),
-		 virt_to_bus(&(p_eth_port_ctrl->p_tx_desc_area[tx_curr_desc])));
+		 (u32)&(p_eth_port_ctrl->p_tx_desc_area[tx_curr_desc]));
 
 	/* Assignment of Rx CRDP of given queue */
 	rx_curr_desc = p_eth_port_ctrl->rx_curr_desc_q;
@@ -2313,21 +2412,23 @@
 		p_tx_desc[ix].byte_cnt = 0x0000;
 		p_tx_desc[ix].l4i_chk = 0x0000;
 		p_tx_desc[ix].cmd_sts = 0x00000000;
-		p_tx_desc[ix].next_desc_ptr = virt_to_bus(&(p_tx_desc[ix+1]));
+		p_tx_desc[ix].next_desc_ptr = (u32)&(p_tx_desc[ix+1]);
 		p_tx_desc[ix].buf_ptr = 0x00000000;
 		dma_cache_wback_inv((unsigned long)&(p_tx_desc[ix]), sizeof(ETH_TX_DESC));
 		p_eth_port_ctrl->tx_skb[ix] = NULL;
 	}
 
 	/* Closing Tx descriptors ring */
-	p_tx_desc[tx_desc_num-1].next_desc_ptr = virt_to_bus(&(p_tx_desc[0]));
+	p_tx_desc[tx_desc_num-1].next_desc_ptr = (u32)&(p_tx_desc[0]);
 	dma_cache_wback_inv((unsigned long)&(p_tx_desc[tx_desc_num-1]),
 			sizeof(ETH_TX_DESC));
 
 	/* Set Tx desc pointer in driver struct. */
 	p_eth_port_ctrl->tx_curr_desc_q = 0;
 	p_eth_port_ctrl->tx_used_desc_q = 0;
-
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        p_eth_port_ctrl->tx_first_desc_q = 0;
+#endif
 	/* Init Tx ring base and size parameters */
 	p_eth_port_ctrl->p_tx_desc_area = (ETH_TX_DESC*) tx_desc_base_addr;
 	p_eth_port_ctrl->tx_desc_area_size = tx_desc_num * sizeof(ETH_TX_DESC);
@@ -2365,6 +2466,127 @@
  *      ETH_OK otherwise.
  *
  *******************************************************************************/
+#ifdef  MV64340_CHECKSUM_OFFLOAD_TX
+/*
+ * Modified to include the first descriptor pointer in case of SG
+ */
+static ETH_FUNC_RET_STATUS eth_port_send(ETH_PORT_INFO * p_eth_port_ctrl,
+                                         PKT_INFO * p_pkt_info)
+{
+        int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc;
+        volatile ETH_TX_DESC* current_descriptor;
+        volatile ETH_TX_DESC* first_descriptor;
+        u32 command_status, first_chip_ptr;
+
+        /* Do not process Tx ring in case of Tx ring resource error */
+        if (p_eth_port_ctrl->tx_resource_err == true)
+                return ETH_QUEUE_FULL;
+
+        /* Get the Tx Desc ring indexes */
+        tx_desc_curr = p_eth_port_ctrl->tx_curr_desc_q;
+        tx_desc_used = p_eth_port_ctrl->tx_used_desc_q;
+
+        current_descriptor = &(p_eth_port_ctrl->p_tx_desc_area[tx_desc_curr]);
+        if (current_descriptor == NULL)
+                return ETH_ERROR;
+
+        tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE;
+        command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
+
+        if (command_status & ETH_TX_FIRST_DESC) {
+                tx_first_desc = tx_desc_curr;
+                p_eth_port_ctrl->tx_first_desc_q = tx_first_desc;
+
+                /* fill first descriptor */
+                first_descriptor = &(p_eth_port_ctrl->p_tx_desc_area[tx_desc_curr]);
+                first_descriptor->l4i_chk = p_pkt_info->l4i_chk;
+                first_descriptor->cmd_sts = command_status;
+                first_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+                first_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+                first_descriptor->next_desc_ptr = (u32)&(p_eth_port_ctrl->p_tx_desc_area[tx_next_desc]);
+                dma_cache_wback_inv((unsigned long)first_descriptor, sizeof(ETH_TX_DESC));
+		wmb();
+        }
+        else {
+                tx_first_desc = p_eth_port_ctrl->tx_first_desc_q;
+                first_descriptor = &(p_eth_port_ctrl->p_tx_desc_area[tx_first_desc]);
+                if (first_descriptor == NULL) {
+                        printk("First desc is NULL !!\n");
+                        return ETH_ERROR;
+                }
+                if (command_status & ETH_TX_LAST_DESC)
+                        current_descriptor->next_desc_ptr = 0x00000000;
+                else {
+                        command_status |= ETH_BUFFER_OWNED_BY_DMA;
+                        current_descriptor->next_desc_ptr = (u32)&(p_eth_port_ctrl->p_tx_desc_area[tx_next_desc]);
+                }
+        }
+
+        if (p_pkt_info->byte_cnt < 8) {
+                printk(" < 8 problem \n");
+                return ETH_ERROR;
+        }
+
+        current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+        current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+        current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
+        current_descriptor->cmd_sts = command_status;
+        dma_cache_wback_inv((unsigned long)current_descriptor, sizeof(ETH_TX_DESC));
+
+        p_eth_port_ctrl->tx_skb[tx_desc_curr] =
+                (struct sk_buff*)p_pkt_info->return_info;
+
+	dma_cache_wback_inv((unsigned long)p_eth_port_ctrl, sizeof(ETH_PORT_INFO));
+        wmb();
+
+        /* Set last desc with DMA ownership and interrupt enable. */
+        if (command_status & ETH_TX_LAST_DESC) {
+                current_descriptor->cmd_sts = command_status |
+                                        ETH_TX_ENABLE_INTERRUPT |
+                                        ETH_BUFFER_OWNED_BY_DMA;
+
+                if (!(command_status & ETH_TX_FIRST_DESC) ) {
+                        first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA;
+                        dma_cache_wback_inv((unsigned long)first_descriptor, sizeof(ETH_TX_DESC));
+                }
+                dma_cache_wback_inv((unsigned long)current_descriptor, sizeof(ETH_TX_DESC));
+                wmb();
+
+                first_chip_ptr = MV_READ_DATA(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(p_eth_port_ctrl->port_num));
+
+                /* Apply send command */
+                if (first_chip_ptr == 0x00000000) {
+                        MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(p_eth_port_ctrl->port_num), (u32)&(p_eth_port_ctrl->p_tx_desc_area[tx_first_desc]));
+                }
+
+                ETH_ENABLE_TX_QUEUE(p_eth_port_ctrl->port_num);
+
+           /* Finish Tx packet. Update first desc in case of Tx resource error */
+                tx_first_desc = tx_next_desc;
+                p_eth_port_ctrl->tx_first_desc_q = tx_first_desc;
+        }
+        else {
+                if (! (command_status & ETH_TX_FIRST_DESC) ) {
+                        current_descriptor->cmd_sts = command_status;
+                        dma_cache_wback_inv((unsigned long)current_descriptor,
+                                                        sizeof(ETH_TX_DESC));
+                        wmb();
+                }
+        }
+
+        /* Check for ring index overlap in the Tx desc ring */
+        if (tx_next_desc == tx_desc_used) {
+                p_eth_port_ctrl->tx_resource_err = true;
+                p_eth_port_ctrl->tx_curr_desc_q = tx_first_desc;
+                return ETH_QUEUE_LAST_RESOURCE;
+        }
+
+        p_eth_port_ctrl->tx_curr_desc_q = tx_next_desc;
+        dma_cache_wback_inv((unsigned long) p_eth_port_ctrl, sizeof(ETH_PORT_INFO));
+        wmb();
+        return ETH_OK;
+}
+#else
 static ETH_FUNC_RET_STATUS eth_port_send(ETH_PORT_INFO * p_eth_port_ctrl,
 					 PKT_INFO * p_pkt_info)
 {
@@ -2431,6 +2653,7 @@
 
 	return ETH_OK;
 }
+#endif
 
 /*******************************************************************************
  * eth_tx_return_desc - Free all used Tx descriptors
@@ -2460,12 +2683,18 @@
 					      PKT_INFO * p_pkt_info)
 {
 	int tx_desc_used, tx_desc_curr;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        int tx_first_desc;
+#endif
 	volatile ETH_TX_DESC *p_tx_desc_used;
 	unsigned int command_status;
 
 	/* Get the Tx Desc ring indexes */
 	tx_desc_curr = p_eth_port_ctrl->tx_curr_desc_q;
 	tx_desc_used = p_eth_port_ctrl->tx_used_desc_q;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        tx_first_desc = p_eth_port_ctrl->tx_first_desc_q;
+#endif
 	p_tx_desc_used = &(p_eth_port_ctrl->p_tx_desc_area[tx_desc_used]);
 
 	/* XXX Sanity check */
@@ -2475,14 +2704,19 @@
 	command_status = p_tx_desc_used->cmd_sts;
 
 	/* Still transmitting... */
+#ifndef MV64340_CHECKSUM_OFFLOAD_TX
 	if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) {
 	  dma_cache_wback_inv((unsigned long)p_tx_desc_used,
 				    sizeof(ETH_TX_DESC));
 		return ETH_RETRY;
 	}
-
+#endif
 	/* Stop release. About to overlap the current available Tx descriptor */
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+	if ((tx_desc_used == tx_first_desc) &&
+#else
 	if ((tx_desc_used == tx_desc_curr) &&
+#endif
 	    (p_eth_port_ctrl->tx_resource_err == false)) {
 	    dma_cache_wback_inv((unsigned long)p_tx_desc_used,
 				    sizeof(ETH_TX_DESC));
@@ -2640,7 +2874,6 @@
 	return ETH_OK;
 }
 
-#ifdef MDD_CUT
 /*******************************************************************************
  * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path
  *
@@ -2713,6 +2946,7 @@
 	return coal;
 }
 
+#ifdef MDD_CUT
 /*******************************************************************************
  * eth_b_copy - Copy bytes from source to destination
  *
diff -urN linux-2.4.23-bk1/drivers/net/mv64340_eth.h linux-2.4.23-bk2/drivers/net/mv64340_eth.h
--- linux-2.4.23-bk1/drivers/net/mv64340_eth.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/mv64340_eth.h	2003-12-03 02:49:52.000000000 -0800
@@ -55,6 +55,12 @@
 #define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1	/* main high register, bit1 */
 #define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2	/* main high register, bit1 */
 
+/* Checksum offload for Tx works */
+#define  MV64340_CHECKSUM_OFFLOAD_TX	1
+#define	 MV64340_NAPI			1
+#define	 MV64340_TX_FAST_REFILL		1
+#undef	 MV64340_COAL
+
 /* 
  * Number of RX / TX descriptors on RX / TX rings.
  * Note that allocating RX descriptors is done by allocating the RX
@@ -69,8 +75,10 @@
 /* Default RX ring size is 400 descriptors */
 #define MV64340_RX_QUEUE_SIZE 400
 
-#define MV64340_TX_COAL 200
-#define MV64340_RX_COAL 200
+#define MV64340_TX_COAL 100
+#ifdef MV64340_COAL
+#define MV64340_RX_COAL 100
+#endif
 
 /* Private data structure used for ethernet device */
 struct mv64340_eth_priv {
@@ -151,9 +159,9 @@
 
 /* Default sdma control value */
 #define PORT_SDMA_CONFIG_VALUE			\
-			 ETH_RX_BURST_SIZE_4_64BIT 	|	\
+			 ETH_RX_BURST_SIZE_16_64BIT 	|	\
 			 GT_ETH_IPG_INT_RX(0) 		|	\
-			 ETH_TX_BURST_SIZE_4_64BIT;
+			 ETH_TX_BURST_SIZE_16_64BIT;
 
 #define GT_ETH_IPG_INT_RX(value)                \
             ((value & 0x3fff) << 8)
@@ -173,7 +181,7 @@
 			ETH_DTE_ADV_0 				|	\
 			ETH_DISABLE_AUTO_NEG_BYPASS		|	\
 			ETH_AUTO_NEG_NO_CHANGE 			|	\
-			ETH_MAX_RX_PACKET_1552BYTE 		|	\
+			ETH_MAX_RX_PACKET_9700BYTE 		|	\
 			ETH_CLR_EXT_LOOPBACK 			|	\
 			ETH_SET_FULL_DUPLEX_MODE 		|	\
 			ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
@@ -554,6 +562,13 @@
 
 	/* Next available and first returning Tx resource */
 	int tx_curr_desc_q, tx_used_desc_q;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        int tx_first_desc_q;
+#endif
+
+#ifdef MV64340_TX_FAST_REFILL
+	u32	tx_clean_threshold;
+#endif
 
 	/* Tx/Rx rings size and base variables fields. For driver use */
 	volatile ETH_RX_DESC *p_rx_desc_area;
@@ -563,7 +578,7 @@
 	volatile ETH_TX_DESC *p_tx_desc_area;
 	unsigned int tx_desc_area_size;
 	struct sk_buff* tx_skb[MV64340_TX_QUEUE_SIZE];
-
+	struct tq_struct tx_timeout_task;
 } ETH_PORT_INFO;
 
 
@@ -578,13 +593,11 @@
 				    unsigned int value);
 static unsigned int ethernet_get_config_reg(ETH_PORT eth_port_num);
 
-#ifdef MDD_CUT
 /* Interrupt Coalesting functions */
 static unsigned int eth_port_set_rx_coal(ETH_PORT, unsigned int,
 					 unsigned int);
 static unsigned int eth_port_set_tx_coal(ETH_PORT, unsigned int,
 					 unsigned int);
-#endif
 
 /* Port MAC address routines */
 static void eth_port_uc_addr_set(ETH_PORT eth_port_num,
diff -urN linux-2.4.23-bk1/drivers/net/pppoe.c linux-2.4.23-bk2/drivers/net/pppoe.c
--- linux-2.4.23-bk1/drivers/net/pppoe.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/pppoe.c	2003-12-03 02:49:52.000000000 -0800
@@ -365,7 +365,8 @@
 		if (!__pppoe_xmit( relay_po->sk , skb))
 			goto abort_put;
 	} else {
-		sock_queue_rcv_skb(sk, skb);
+		if (sock_queue_rcv_skb(sk, skb))
+			goto abort_kfree;
 	}
 
 	return NET_RX_SUCCESS;
diff -urN linux-2.4.23-bk1/drivers/net/sb1250-mac.c linux-2.4.23-bk2/drivers/net/sb1250-mac.c
--- linux-2.4.23-bk1/drivers/net/sb1250-mac.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.23-bk2/drivers/net/sb1250-mac.c	2003-12-03 02:49:52.000000000 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Broadcom Corporation
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -17,10 +17,10 @@
  */
 
 /*
-  This driver is designed for the Broadcom BCM12500 SOC chip's built-in
+  This driver is designed for the Broadcom SiByte SOC built-in
   Ethernet controllers.
   
-  The author may be reached as mpl@broadcom.com
+  Written by Mitch Lichtenberg at Broadcom Corp.
 */
 
 
@@ -31,6 +31,7 @@
    These may be modified when a driver module is loaded. */
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int noisy_mii = 1;		/* mii status msgs */
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
@@ -44,8 +45,10 @@
 static int full_duplex[MAX_UNITS] = {-1, -1, -1};
 #endif
 
+#ifdef CONFIG_SBMAC_COALESCE
 static int int_pktcnt = 0;
 static int int_timeout = 0;
+#endif
 
 /* Operational parameters that usually are not changed. */
 
@@ -74,8 +77,7 @@
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/64bit.h>
+#include <asm/cache.h>
 
 /* This is only here until the firmware is ready.  In that case,
    the firmware leaves the ethernet address in the register for us. */
@@ -89,26 +91,29 @@
 /* These identify the driver base version and may not be removed. */
 #if 0
 static char version1[] __devinitdata =
-"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n";
+"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
 #endif
 
 
 
-MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)");
-MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver");
+MODULE_AUTHOR("Mitch Lichtenberg (Broadcom Corp.)");
+MODULE_DESCRIPTION("Broadcom SiByte SOC GB Ethernet driver");
 MODULE_PARM(debug, "i");
+MODULE_PARM(noisy_mii, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 MODULE_PARM(int_pktcnt, "i");
 MODULE_PARM(int_timeout, "i");
 
+#include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_defs.h>
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_mac.h>
 #include <asm/sibyte/sb1250_dma.h>
 #include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_scd.h>		/* Only to check SOC part number. */
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/64bit.h>
 
 
 /**********************************************************************
@@ -117,8 +122,6 @@
 
 
 typedef unsigned long sbmac_port_t;
-typedef uint64_t sbmac_physaddr_t;
-typedef uint64_t sbmac_enetaddr_t;
 
 typedef enum { sbmac_speed_auto, sbmac_speed_10,
 	       sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
@@ -142,17 +145,11 @@
 			  (d)->sbdma_dscrtable : (d)->f+1)
 
 
-#define CACHELINESIZE 32
-#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE)
-#define KMALLOC(x) kmalloc((x),GFP_KERNEL)
-#define KFREE(x) kfree(x)
-#define KVTOPHYS(x) virt_to_bus((void *)(x))
+#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
 
+#define SBMAC_READCSR(t)	in64((unsigned long)t)
+#define SBMAC_WRITECSR(t,v)	out64(v, (unsigned long)t)
  
-#define SBMAC_READCSR(t)    (in64((unsigned long)(t)))
-#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t)))
-
-#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
 
 #define SBMAC_MAX_TXDESCR	32
 #define SBMAC_MAX_RXDESCR	32
@@ -172,7 +169,6 @@
 } sbdmadscr_t;
 
 typedef unsigned long paddr_t;
-typedef unsigned long vaddr_t;
 
 /**********************************************************************
  *  DMA Controller structure
@@ -190,8 +186,8 @@
 	int		 sbdma_txdir;       /* direction (1=transmit) */
 	int		 sbdma_maxdescr;	/* total # of descriptors in ring */
 #ifdef CONFIG_SBMAC_COALESCE
-        int              sbdma_int_pktcnt;  /* # descriptors rx before interrupt*/
-        int              sbdma_int_timeout; /* # usec rx interrupt */
+	int		 sbdma_int_pktcnt;  /* # descriptors rx/tx before interrupt*/
+	int		 sbdma_int_timeout; /* # usec rx/tx interrupt */
 #endif
 
 	sbmac_port_t     sbdma_config0;	/* DMA config register 0 */
@@ -212,7 +208,6 @@
 	paddr_t          sbdma_dscrtable_phys; /* and also the phys addr */
 	sbdmadscr_t     *sbdma_addptr;	/* next dscr for sw to add */
 	sbdmadscr_t     *sbdma_remptr;	/* next dscr for sw to remove */
-	
 } sbmacdma_t;
 
 
@@ -232,10 +227,10 @@
 	struct net_device_stats sbm_stats; 
 	int sbm_devflags;			/* current device flags */
 
-        int	     sbm_phy_oldbmsr;
-        int	     sbm_phy_oldanlpar;
-        int	     sbm_phy_oldk1stsr;
-        int          sbm_phy_oldlinkstat;
+	int	     sbm_phy_oldbmsr;
+	int	     sbm_phy_oldanlpar;
+	int	     sbm_phy_oldk1stsr;
+	int	     sbm_phy_oldlinkstat;
 	int sbm_buffersize;
 	
 	unsigned char sbm_phys[2];
@@ -244,7 +239,7 @@
 	 * Controller-specific things
 	 */
 	
-	sbmac_port_t     sbm_base;          /* MAC's base address */
+	unsigned long	sbm_base;          /* MAC's base address */
 	sbmac_state_t    sbm_state;         /* current state */
 	
 	sbmac_port_t     sbm_macenable;	/* MAC Enable Register */
@@ -260,13 +255,12 @@
 	sbmac_duplex_t   sbm_duplex;	/* current duplex */
 	sbmac_fc_t       sbm_fc;		/* current flow control setting */
 	
-	u_char           sbm_hwaddr[ETHER_ADDR_LEN];
+	unsigned char    sbm_hwaddr[ETHER_ADDR_LEN];
 	
 	sbmacdma_t       sbm_txdma;		/* for now, only use channel 0 */
 	sbmacdma_t       sbm_rxdma;
 	int              rx_hw_checksum;
 	int 		 sbe_idx;
-	
 };
 
 
@@ -295,12 +289,11 @@
 static void sbmac_channel_stop(struct sbmac_softc *s);
 static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
 static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
-/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/
 static uint64_t sbmac_addr2reg(unsigned char *ptr);
 static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
 static void sbmac_setmulti(struct sbmac_softc *sc);
-static int sbmac_init(struct net_device *dev);
+static int sbmac_init(struct net_device *dev, int idx);
 static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
 static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
 
@@ -325,7 +318,6 @@
  ********************************************************************* */
 
 static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
-static uint64_t chip_revision;
 
 
 /**********************************************************************
@@ -347,8 +339,8 @@
 #define BMCR_DUPLEX    0x0100
 #define BMCR_COLTEST   0x0080
 #define BMCR_SPEED1    0x0040
-#define BMCR_SPEED1000 (BMCR_SPEED1)
-#define BMCR_SPEED100  (BMCR_SPEED0)
+#define BMCR_SPEED1000	BMCR_SPEED1
+#define BMCR_SPEED100	BMCR_SPEED0
 #define BMCR_SPEED10 	0
 
 #define BMSR_100BT4	0x8000
@@ -511,7 +503,8 @@
 	curmask = 1 << (bitcnt - 1);
 	
 	for (i = 0; i < bitcnt; i++) {
-		if (data & curmask) bits |= M_MAC_MDIO_OUT;
+		if (data & curmask)
+			bits |= M_MAC_MDIO_OUT;
 		else bits &= ~M_MAC_MDIO_OUT;
 		SBMAC_WRITECSR(s->sbm_mdio,bits);
 		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
@@ -533,7 +526,7 @@
  *  	   regidx = index of register to read
  *  	   
  *  Return value:
- *  	   value read, or 0 if an error occured.
+ *  	   value read, or 0 if an error occurred.
  ********************************************************************* */
 
 static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
@@ -575,7 +568,7 @@
 	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
 	
 	/* 
-	 * If an error occured, the PHY will signal '1' back
+	 * If an error occurred, the PHY will signal '1' back
 	 */
 	error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN;
 	
@@ -592,7 +585,8 @@
 		regval <<= 1;
 		
 		if (error == 0) {
-			if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1;
+			if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN)
+				regval |= 1;
 		}
 		
 		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
@@ -602,7 +596,8 @@
 	/* Switch back to output */
 	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
 	
-	if (error == 0) return regval;
+	if (error == 0)
+		return regval;
 	return 0;
 }
 
@@ -672,66 +667,68 @@
 	d->sbdma_channel   = chan;
 	d->sbdma_txdir     = txrx;
 	
+#if 0
 	/* RMON clearing */
 	s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
+#endif
 
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0);
-	SBMAC_WRITECSR(PKSEG1(
-        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0);
+	SBMAC_WRITECSR(KSEG1ADDR(
+	A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0);
 
 	/* 
 	 * initialize register pointers 
 	 */
 	
 	d->sbdma_config0 = 
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0);
 	d->sbdma_config1 = 
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1));
+		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1);
 	d->sbdma_dscrbase = 
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));
+		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE);
 	d->sbdma_dscrcnt = 
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT));
+		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
 	d->sbdma_curdscr = 	
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR));
+		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
 	
 	/*
 	 * Allocate memory for the ring
@@ -740,47 +737,39 @@
 	d->sbdma_maxdescr = maxdescr;
 	
 	d->sbdma_dscrtable = (sbdmadscr_t *) 
-		KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+		kmalloc(d->sbdma_maxdescr*sizeof(sbdmadscr_t), GFP_KERNEL);
 	
 	memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
 	
 	d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
 	
-	d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable);
+	d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable);
 	
 	/*
 	 * And context table
 	 */
 	
 	d->sbdma_ctxtable = (struct sk_buff **) 
-		KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *));
+		kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL);
 	
 	memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
 	
 #ifdef CONFIG_SBMAC_COALESCE
-        /*
-         * Setup Rx DMA coalescing defaults
-         */
-
-        if ( txrx == DMA_RX ) {
-		if ( int_pktcnt ) {
-                	d->sbdma_int_pktcnt = int_pktcnt;
-		        }
-		else {
-                	d->sbdma_int_pktcnt = 1;
-		        }
+	/*
+	 * Setup Rx/Tx DMA coalescing defaults
+	 */
 
-		if ( int_timeout ) {
-		        d->sbdma_int_timeout = int_timeout;
-		        }
-		else {
-		        d->sbdma_int_timeout = 0;
-		    }
-	        }
-        else {
-                d->sbdma_int_pktcnt = 0;
-                d->sbdma_int_timeout = 0;
-	        }
+	if ( int_pktcnt ) {
+		d->sbdma_int_pktcnt = int_pktcnt;
+	} else {
+		d->sbdma_int_pktcnt = 1;
+	}
+	
+	if ( int_timeout ) {
+		d->sbdma_int_timeout = int_timeout;
+	} else {
+		d->sbdma_int_timeout = 0;
+	}
 #endif
 
 }
@@ -800,43 +789,34 @@
 
 static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
 {
-    /*
-     * Turn on the DMA channel
-     */
+	/*
+	 * Turn on the DMA channel
+	 */
 	
 #ifdef CONFIG_SBMAC_COALESCE
-    if (rxtx == DMA_RX) {
-        SBMAC_WRITECSR(d->sbdma_config1,
+	SBMAC_WRITECSR(d->sbdma_config1,
 		       V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) |
 		       0);
-        SBMAC_WRITECSR(d->sbdma_config0,
-                       M_DMA_EOP_INT_EN |
-                       V_DMA_RINGSZ(d->sbdma_maxdescr) |
-                       V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) |
-                       0);
-	}
-    else {
-	SBMAC_WRITECSR(d->sbdma_config1,0);
 	SBMAC_WRITECSR(d->sbdma_config0,
+		       M_DMA_EOP_INT_EN |
 		       V_DMA_RINGSZ(d->sbdma_maxdescr) |
+		       V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) |
 		       0);
-	}
 #else
-    SBMAC_WRITECSR(d->sbdma_config1,0);
-    SBMAC_WRITECSR(d->sbdma_config0,
-		   V_DMA_RINGSZ(d->sbdma_maxdescr) |
-		   0);
+	SBMAC_WRITECSR(d->sbdma_config1,0);
+	SBMAC_WRITECSR(d->sbdma_config0,
+		       V_DMA_RINGSZ(d->sbdma_maxdescr) |
+		       0);
 #endif
 
-	
-    SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
-	
-    /*
-     * Initialize ring pointers
-     */
-	
-    d->sbdma_addptr = d->sbdma_dscrtable;
-    d->sbdma_remptr = d->sbdma_dscrtable;
+	SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+
+	/*
+	 * Initialize ring pointers
+	 */
+
+	d->sbdma_addptr = d->sbdma_dscrtable;
+	d->sbdma_remptr = d->sbdma_dscrtable;
 }
 
 /**********************************************************************
@@ -921,7 +901,7 @@
 	if (nextdsc == d->sbdma_remptr) {
 		return -ENOSPC;
 	}
-	
+
 	/* 
 	 * Allocate a sk_buff if we don't already have one.  
 	 * If we do have an sk_buff, reset it so that it's empty.
@@ -935,22 +915,22 @@
 	 *    3. The buffer can be aligned such that the IP addresses are 
 	 *       naturally aligned.
 	 *
-	 *  Remember, the SB1250's MAC writes whole cache lines at a time,
+	 *  Remember, the SOCs MAC writes whole cache lines at a time,
 	 *  without reading the old contents first.  So, if the sk_buff's
-	 *  data portion starts in the middle of a cache line, the SB1250
+	 *  data portion starts in the middle of a cache line, the SOC
 	 *  DMA will trash the beginning (and ending) portions.
 	 */
 	
 	if (sb == NULL) {
-		sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN);
+		sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
 		if (sb_new == NULL) {
 			printk(KERN_INFO "%s: sk_buff allocation failed\n",
 			       d->sbdma_eth->sbm_dev->name);
 			return -ENOBUFS;
 		}
-		
-		sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN);
-		
+
+		sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN);
+
 		/* mark skbuff owned by our device */
 		sb_new->dev = d->sbdma_eth->sbm_dev;
 	}
@@ -958,7 +938,7 @@
 		sb_new = sb;
 		/* 
 		 * nothing special to reinit buffer, it's already aligned
-		 * and sb->tail already points to a good place.
+		 * and sb->data already points to a good place.
 		 */
 	}
 	
@@ -967,18 +947,18 @@
 	 */
 	
 #ifdef CONFIG_SBMAC_COALESCE
-        /*
-         * Do not interrupt per DMA transfer.
-         */
-        dsc->dscr_a = KVTOPHYS(sb_new->tail) |
-                V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
-                0;
+	/*
+	 * Do not interrupt per DMA transfer.
+	 */
+	dsc->dscr_a = virt_to_phys(sb_new->tail) |
+		V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+		0;
 #else
-	dsc->dscr_a = KVTOPHYS(sb_new->tail) |
+	dsc->dscr_a = virt_to_phys(sb_new->tail) |
 		V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
 		M_DMA_DSCRA_INTERRUPT;
 #endif
-	
+
 	/* receiving: no options */
 	dsc->dscr_b = 0;
 	
@@ -1057,12 +1037,14 @@
 	 * while doing the calculation.
 	 */
 	
-	phys = KVTOPHYS(sb->data);
-	ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1)));
-	
+	phys = virt_to_phys(sb->data);
+	ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1)));
+
 	dsc->dscr_a = phys | 
 		V_DMA_DSCRA_A_SIZE(ncb) |
+#ifndef CONFIG_SBMAC_COALESCE
 		M_DMA_DSCRA_INTERRUPT |
+#endif
 		M_DMA_ETHTX_SOP;
 	
 	/* transmitting: set outbound options and length */
@@ -1139,7 +1121,8 @@
 	int idx;
 	
 	for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
-		if (sbdma_add_rcvbuffer(d,NULL) != 0) break;
+		if (sbdma_add_rcvbuffer(d,NULL) != 0)
+			break;
 	}
 }
 
@@ -1190,7 +1173,8 @@
 		 * the hardware is working on right now.
 		 */
 		
-		if (curidx == hwidx) break;
+		if (curidx == hwidx)
+			break;
 		
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
@@ -1211,49 +1195,47 @@
 		if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
 			
 			/*
-			 * Set length into the packet
-			 */
-			skb_put(sb,len);
-			
-       			/*
 			 * Add a new buffer to replace the old one.  If we fail
 			 * to allocate a buffer, we're going to drop this
 			 * packet and put it right back on the receive ring.
 			 */
 			
 			if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
-			    sbdma_add_rcvbuffer(d,sb);	/* re-add old buffer */
-			    }
-			else {
-			    /*
-			     * Buffer has been replaced on the receive ring.
-			     * Pass the buffer to the kernel
-			     */
-			    sc->sbm_stats.rx_bytes += len;
-			    sc->sbm_stats.rx_packets++;
-			    sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
-                            if (sc->rx_hw_checksum == ENABLE) {
-			    /* if the ip checksum is good indicate in skb.
-		                else set CHECKSUM_NONE as device failed to
-					checksum the packet */
-
-			       if (((dsc->dscr_b) |M_DMA_ETHRX_BADTCPCS) ||
-			     	  ((dsc->dscr_a)| M_DMA_ETHRX_BADIP4CS)){
-				  sb->ip_summed = CHECKSUM_NONE;
-			       } else {
-				 printk(KERN_DEBUG "hw checksum fail .\n");
-				 sb->ip_summed = CHECKSUM_UNNECESSARY;
-			       }
-			    } /*rx_hw_checksum */
-
-			    netif_rx(sb);
-			    }
-		}
-		else {
+				sc->sbm_stats.rx_dropped++;
+				sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+			} else {
+				/*
+				 * Set length into the packet
+				 */
+				skb_put(sb,len);
+				
+				/*
+				 * Buffer has been replaced on the
+				 * receive ring.  Pass the buffer to
+				 * the kernel
+				 */
+				sc->sbm_stats.rx_bytes += len;
+				sc->sbm_stats.rx_packets++;
+				sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+				/* Check hw IPv4/TCP checksum if supported */
+				if (sc->rx_hw_checksum == ENABLE) {
+					if (!((dsc->dscr_a) & M_DMA_ETHRX_BADIP4CS) &&
+					    !((dsc->dscr_a) & M_DMA_ETHRX_BADTCPCS)) {
+						sb->ip_summed = CHECKSUM_UNNECESSARY;
+						/* don't need to set sb->csum */
+					} else {
+						sb->ip_summed = CHECKSUM_NONE;
+					}
+				}
+				
+				netif_rx(sb);
+			}
+		} else {
 			/*
 			 * Packet was mangled somehow.  Just drop it and
 			 * put it back on the receive ring.
 			 */
+			sc->sbm_stats.rx_errors++;
 			sbdma_add_rcvbuffer(d,sb);
 		}
 		
@@ -1309,36 +1291,17 @@
 		 */
 		
 		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
-		{
-			/* XXX This is gross, ugly, and only here because justin hacked it
-			   in to fix a problem without really understanding it. 
-			   
-			   It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts.
-			   So then the Read below returns zero, making hwidx a negative number, and anti-hilarity
-			   ensues.
-			   
-			   I'm guessing there's a proper fix involving clearing out interrupt state from old packets
-			   before enabling interrupts, but I'm not sure.  
-
-			   Anyways, this hack seems to work, and is Good Enough for 11 PM.  :)
-			   
-			   -Justin
-			*/
-			  
-			uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr);
-			if (!tmp) {
-				break;
-			}
-			hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -
-					d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
-		}
+		hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
 		/*
 		 * If they're the same, that means we've processed all
 		 * of the descriptors up to (but not including) the one that
 		 * the hardware is working on right now.
 		 */
 		
-		if (curidx == hwidx) break;
+		if (curidx == hwidx)
+			break;
 		
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
@@ -1405,14 +1368,14 @@
 	 * figure out the addresses of some ports 
 	 */
 	
-	s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE);
-	s->sbm_maccfg    = PKSEG1(s->sbm_base + R_MAC_CFG);
-	s->sbm_fifocfg   = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG);
-	s->sbm_framecfg  = PKSEG1(s->sbm_base + R_MAC_FRAMECFG);
-	s->sbm_rxfilter  = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG);
-	s->sbm_isr       = PKSEG1(s->sbm_base + R_MAC_STATUS);
-	s->sbm_imr       = PKSEG1(s->sbm_base + R_MAC_INT_MASK);
-	s->sbm_mdio      = PKSEG1(s->sbm_base + R_MAC_MDIO);
+	s->sbm_macenable = s->sbm_base + R_MAC_ENABLE;
+	s->sbm_maccfg    = s->sbm_base + R_MAC_CFG;
+	s->sbm_fifocfg   = s->sbm_base + R_MAC_THRSH_CFG;
+	s->sbm_framecfg  = s->sbm_base + R_MAC_FRAMECFG;
+	s->sbm_rxfilter  = s->sbm_base + R_MAC_ADFILTER_CFG;
+	s->sbm_isr       = s->sbm_base + R_MAC_STATUS;
+	s->sbm_imr       = s->sbm_base + R_MAC_INT_MASK;
+	s->sbm_mdio      = s->sbm_base + R_MAC_MDIO;
 
 	s->sbm_phys[0]   = 1;
 	s->sbm_phys[1]   = 0;
@@ -1451,12 +1414,12 @@
 static void sbdma_uninitctx(struct sbmacdma_s *d)
 {
 	if (d->sbdma_dscrtable) {
-		KFREE(d->sbdma_dscrtable);
+		kfree(d->sbdma_dscrtable);
 		d->sbdma_dscrtable = NULL;
 	}
 	
 	if (d->sbdma_ctxtable) {
-		KFREE(d->sbdma_ctxtable);
+		kfree(d->sbdma_ctxtable);
 		d->sbdma_ctxtable = NULL;
 	}
 }
@@ -1486,13 +1449,14 @@
 	uint64_t reg;
 	sbmac_port_t port;
 	uint64_t cfg,fifo,framecfg;
-	int idx;
+	int idx, th_value;
 	
 	/*
 	 * Don't do this if running
 	 */
 
-	if (s->sbm_state == sbmac_state_on) return;
+	if (s->sbm_state == sbmac_state_on)
+		return;
 	
 	/*
 	 * Bring the controller out of reset, but leave it off.
@@ -1519,31 +1483,35 @@
 		0;
 	
 	/* 
-	 * Be sure that RD_THRSH+WR_THRSH <= 32
+	 * Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars
+	 * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above
 	 * Use a larger RD_THRSH for gigabit
 	 */
+	if (periph_rev >= 2) 
+		th_value = 64;
+	else 
+		th_value = 28;
 
 	fifo = V_MAC_TX_WR_THRSH(4) |	/* Must be '4' or '8' */
 		((s->sbm_speed == sbmac_speed_1000)
-		 ? V_MAC_TX_RD_THRSH(28) : V_MAC_TX_RD_THRSH(4)) |
+		 ? V_MAC_TX_RD_THRSH(th_value) : V_MAC_TX_RD_THRSH(4)) |
 		V_MAC_TX_RL_THRSH(4) |
 		V_MAC_RX_PL_THRSH(4) |
 		V_MAC_RX_RD_THRSH(4) |	/* Must be '4' */
 		V_MAC_RX_PL_THRSH(4) |
 		V_MAC_RX_RL_THRSH(8) |
 		0;
-	
+
 	framecfg = V_MAC_MIN_FRAMESZ_DEFAULT |
 		V_MAC_MAX_FRAMESZ_DEFAULT |
 		V_MAC_BACKOFF_SEL(1);
-	
-	
+
 	/*
 	 * Clear out the hash address map 
 	 */
 	
-	port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE);
-        for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+	port = s->sbm_base + R_MAC_HASH_BASE;
+	for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
 		SBMAC_WRITECSR(port,0);
 		port += sizeof(uint64_t);
 	}
@@ -1552,7 +1520,7 @@
 	 * Clear out the exact-match table
 	 */
 	
-	port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+	port = s->sbm_base + R_MAC_ADDR_BASE;
 	for (idx = 0; idx < MAC_ADDR_COUNT; idx++) {
 		SBMAC_WRITECSR(port,0);
 		port += sizeof(uint64_t);
@@ -1562,14 +1530,14 @@
 	 * Clear out the DMA Channel mapping table registers
 	 */
 	
-	port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE);
+	port = s->sbm_base + R_MAC_CHUP0_BASE;
 	for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
 		SBMAC_WRITECSR(port,0);
 		port += sizeof(uint64_t);
 	}
 
 
-	port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE);
+	port = s->sbm_base + R_MAC_CHLO0_BASE;
 	for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
 		SBMAC_WRITECSR(port,0);
 		port += sizeof(uint64_t);
@@ -1582,13 +1550,13 @@
 	
 	reg = sbmac_addr2reg(s->sbm_hwaddr);
 	
-	port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+	port = s->sbm_base + R_MAC_ADDR_BASE;
 	SBMAC_WRITECSR(port,reg);
-	port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR);
+	port = s->sbm_base + R_MAC_ETHERNET_ADDR;
 
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
 	/*
-	 * Pass1 SB1250s do not receive packets addressed to the
+	 * Pass1 SOCs do not receive packets addressed to the
 	 * destination address in the R_MAC_ETHERNET_ADDR register.
 	 * Set the value to zero.
 	 */
@@ -1646,7 +1614,7 @@
 	 * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
 	 */
 	SBMAC_WRITECSR(s->sbm_imr,
-		       (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
 		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0));
 #else
 	/*
@@ -1702,7 +1670,8 @@
 {
 	/* don't do this if already stopped */
 	
-	if (s->sbm_state == sbmac_state_off) return;
+	if (s->sbm_state == sbmac_state_off)
+		return;
 	
 	/* don't accept any packets, disable all interrupts */
 	
@@ -1795,7 +1764,8 @@
 {
 	uint64_t reg;
 	
-	if (sc->sbm_state != sbmac_state_on) return;
+	if (sc->sbm_state != sbmac_state_on)
+		return;
 	
 	if (onoff) {
 		reg = SBMAC_READCSR(sc->sbm_rxfilter);
@@ -1825,15 +1795,15 @@
 {
 	uint64_t reg;
 	
-	reg = SBMAC_READCSR(sc->sbm_rxfilter);
-	reg &= ~M_MAC_IPHDR_OFFSET;
 	/* Hard code the off set to 15 for now */
-	reg |= 15 << S_MAC_IPHDR_OFFSET;
+	reg = SBMAC_READCSR(sc->sbm_rxfilter);
+	reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15);
 	SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
 	
 	/* read system identification to determine revision */
-	if (sb1250_pass >= K_SYS_REVISION_PASS2) {
-		printk(KERN_INFO "pass2 - enabling Rx rcv tcp checksum\n");
+	if (periph_rev >= 2) {
+		printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
+		       sc->sbm_dev->name);
 		sc->rx_hw_checksum = ENABLE;
 	} else {
 		sc->rx_hw_checksum = DISABLE;
@@ -1841,31 +1811,6 @@
 }
 
 
-#if 0
-/**********************************************************************
- *  SBMAC_INIT_AND_START(sc)
- *  
- *  Stop the channel and restart it.  This is generally used
- *  when we have to do something to the channel that requires
- *  a swift kick.
- *  
- *  Input parameters: 
- *  	   sc - softc
- ********************************************************************* */
-
-static void sbmac_init_and_start(struct sbmac_softc *sc)
-{
-	unsigned long flags;
-	
-	spin_lock_irqsave(&(sc->sbm_lock),flags);
-	
-	sbmac_set_channel_state(sc,sbmac_state_on);
-	
-	spin_unlock_irqrestore(&(sc->sbm_lock),flags);
-}
-#endif
-
-
 /**********************************************************************
  *  SBMAC_ADDR2REG(ptr)
  *  
@@ -1927,7 +1872,8 @@
 	
 	s->sbm_speed = speed;
 	
-	if (s->sbm_state == sbmac_state_on) return 0;	/* save for next restart */
+	if (s->sbm_state == sbmac_state_on)
+		return 0;	/* save for next restart */
 
 	/*
 	 * Read current register values 
@@ -1987,7 +1933,6 @@
 	SBMAC_WRITECSR(s->sbm_maccfg,cfg);
 	
 	return 1;
-	
 }
 
 /**********************************************************************
@@ -2017,7 +1962,8 @@
 	s->sbm_duplex = duplex;
 	s->sbm_fc = fc;
 	
-	if (s->sbm_state == sbmac_state_on) return 0;	/* save for next restart */
+	if (s->sbm_state == sbmac_state_on)
+		return 0;	/* save for next restart */
 	
 	/*
 	 * Read current register values 
@@ -2116,7 +2062,8 @@
 		
 		isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
 		
-		if (isr == 0) break;
+		if (isr == 0)
+			break;
 		
 		/*
 		 * Transmits on channel 0
@@ -2151,7 +2098,6 @@
 			sbdma_rx_process(sc,&(sc->sbm_rxdma));
 		}
 	}
-	
 }
 
 
@@ -2224,12 +2170,12 @@
 	 */
 	
 	for (idx = 1; idx < MAC_ADDR_COUNT; idx++) {
-		port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+		port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t));
 		SBMAC_WRITECSR(port,0);	
 	}
 	
 	for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
-		port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)));
+		port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t));
 		SBMAC_WRITECSR(port,0);	
 	}
 	
@@ -2266,8 +2212,7 @@
 	mclist = dev->mc_list;
 	while (mclist && (idx < MAC_ADDR_COUNT)) {
 		reg = sbmac_addr2reg(mclist->dmi_addr);
-		port = PKSEG1(sc->sbm_base + 
-			      R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+		port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t));
 		SBMAC_WRITECSR(port,reg);
 		idx++;
 		mclist = mclist->next;
@@ -2304,10 +2249,14 @@
 {
 	int digit;
 	
-	if ((str >= '0') && (str <= '9')) digit = str - '0';
-	else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10;
-	else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10;
-	else return -1;
+	if ((str >= '0') && (str <= '9'))
+		digit = str - '0';
+	else if ((str >= 'a') && (str <= 'f'))
+		digit = str - 'a' + 10;
+	else if ((str >= 'A') && (str <= 'F'))
+		digit = str - 'A' + 10;
+	else
+		return -1;
 	
 	return digit;
 }
@@ -2326,16 +2275,18 @@
  *  	   0 if ok, else -1
  ********************************************************************* */
 
-static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
+static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr)
 {
 	int digit1,digit2;
 	int idx = 6;
 	
 	while (*str && (idx > 0)) {
 		digit1 = sbmac_parse_xdigit(*str);
-		if (digit1 < 0) return -1;
+		if (digit1 < 0)
+			return -1;
 		str++;
-		if (!*str) return -1;
+		if (!*str)
+			return -1;
 		
 		if ((*str == ':') || (*str == '-')) {
 			digit2 = digit1;
@@ -2343,15 +2294,18 @@
 		}
 		else {
 			digit2 = sbmac_parse_xdigit(*str);
-			if (digit2 < 0) return -1;
+			if (digit2 < 0)
+				return -1;
 			str++;
 		}
 		
 		*hwaddr++ = (digit1 << 4) | digit2;
 		idx--;
 		
-		if (*str == '-') str++;
-		if (*str == ':') str++;
+		if (*str == '-')
+			str++;
+		if (*str == ':')
+			str++;
 	}
 	return 0;
 }
@@ -2359,11 +2313,11 @@
 
 static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
 {
-        if (new_mtu >  ENET_PACKET_SIZE)
-                return -EINVAL;
-        _dev->mtu = new_mtu;
+	if (new_mtu >  ENET_PACKET_SIZE)
+		return -EINVAL;
+	_dev->mtu = new_mtu;
 	printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
-        return 0;
+	return 0;
 }
 
 /**********************************************************************
@@ -2378,19 +2332,20 @@
  *  	   status
  ********************************************************************* */
 
-static int sbmac_init(struct net_device *dev)
+static int sbmac_init(struct net_device *dev, int idx)
 {
 	struct sbmac_softc *sc;
-	u_char *eaddr;
+	unsigned char *eaddr;
 	uint64_t ea_reg;
-	int idx;
+	int i;
 	
 	sc = (struct sbmac_softc *)dev->priv;
 	
 	/* Determine controller base address */
 	
-	sc->sbm_base = (sbmac_port_t) dev->base_addr;
+	sc->sbm_base = KSEG1ADDR(dev->base_addr);
 	sc->sbm_dev = dev;
+	sc->sbe_idx = idx;
 	
 	eaddr = sc->sbm_hwaddr;
 	
@@ -2399,16 +2354,15 @@
 	 * for us in the ethernet address register for each mac.
 	 */
 	
-	ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR));
-	SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0);
-	for (idx = 0; idx < 6; idx++) {
-		eaddr[idx] = (uint8_t) (ea_reg & 0xFF);
+	ea_reg = SBMAC_READCSR(sc->sbm_base + R_MAC_ETHERNET_ADDR);
+	SBMAC_WRITECSR(sc->sbm_base + R_MAC_ETHERNET_ADDR, 0);
+	for (i = 0; i < 6; i++) {
+		eaddr[i] = (uint8_t) (ea_reg & 0xFF);
 		ea_reg >>= 8;
 	}
 	
-	
-	for (idx = 0; idx < 6; idx++) {
-		dev->dev_addr[idx] = eaddr[idx];
+	for (i = 0; i < 6; i++) {
+		dev->dev_addr[i] = eaddr[i];
 	}
 	
 	
@@ -2416,8 +2370,8 @@
 	 * Init packet size 
 	 */
 	
-	sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN;
-	
+	sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN;
+
 	/* 
 	 * Initialize context (get pointers to registers and stuff), then
 	 * allocate the memory for the descriptor tables.
@@ -2427,13 +2381,13 @@
 	
 	
 	/*
-	 * Display Ethernet address (this is called during the config process
-	 * so we need to finish off the config message that was being displayed)
+	 * Display Ethernet address (this is called during the config
+	 * process so we need to finish off the config message that
+	 * was being displayed)
 	 */
 	printk(KERN_INFO
-	       "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", 
-	       dev->name,
-	       (unsigned long) sc->sbm_base,
+	       "%s: SiByte Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", 
+	       dev->name, dev->base_addr,
 	       eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
 	
 	/*
@@ -2454,16 +2408,10 @@
 
 	dev->change_mtu         = sb1250_change_mtu;
 
-	if (sb1250_pass >= K_SYS_REVISION_PASS3) {
-		/* In pass3 we do dumb checksum in TX */
-		dev->features |= NETIF_F_IP_CSUM;
-	}
-
-        /* This is needed for PASS2 for Rx H/W checksum feature */
-	sbmac_set_iphdr_offset( sc);
+	/* This is needed for PASS2 for Rx H/W checksum feature */
+	sbmac_set_iphdr_offset(sc);
 	
 	return 0;
-	
 }
 
 
@@ -2478,9 +2426,12 @@
 	}
 	
 	/* 
-	 * map/route interrupt 
+	 * map/route interrupt (clear status first, in case something
+	 * weird is pending; we haven't initialized the mac registers
+	 * yet)
 	 */
-	
+
+	SBMAC_READCSR(sc->sbm_isr);
 	if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) {
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -2490,7 +2441,7 @@
 	 * Configure default speed 
 	 */
 
-	sbmac_mii_poll(sc,1);
+	sbmac_mii_poll(sc,noisy_mii);
 	
 	/*
 	 * Turn on the channel
@@ -2572,7 +2523,8 @@
 	chg = 1;
 	}
 
-    if (chg == 0) return 0;
+    if (chg == 0)
+	    return 0;
 
     p += sprintf(p,"Link speed: ");
 
@@ -2616,9 +2568,6 @@
 	p += sprintf(p,"Unknown");
 	}
 
-#ifdef CONFIG_NET_SB1250_MAC_QUIET
-    noisy = 0;
-#endif
     if (noisy) {
 	    printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
 	    }
@@ -2627,8 +2576,6 @@
 }
 
 
-
-
 static void sbmac_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -2655,19 +2602,19 @@
 	 * Poll the PHY to see what speed we should be running at
 	 */
 
-	if (sbmac_mii_poll(sc,1)) {
-	    if (sc->sbm_state != sbmac_state_off) {
-		/*
-		 * something changed, restart the channel
-		 */
-		if (debug > 1) {
-		    printk("%s: restarting channel because speed changed\n",
-			   sc->sbm_dev->name);
-		    }
-		sbmac_channel_stop(sc);
-		sbmac_channel_start(sc);
+	if (sbmac_mii_poll(sc,noisy_mii)) {
+		if (sc->sbm_state != sbmac_state_off) {
+			/*
+			 * something changed, restart the channel
+			 */
+			if (debug > 1) {
+				printk("%s: restarting channel because speed changed\n",
+				       sc->sbm_dev->name);
+			}
+			sbmac_channel_stop(sc);
+			sbmac_channel_start(sc);
 		}
-	    }
+	}
 	
 	spin_unlock_irq (&sc->sbm_lock);
 	
@@ -2735,7 +2682,8 @@
 	spin_unlock_irqrestore(&sc->sbm_lock, flags);
 	
 	if (msg_flag) {
-		printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis");
+		printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n",
+		       dev->name,(msg_flag==1)?"en":"dis");
 	}
 	
 	/*
@@ -2786,31 +2734,29 @@
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
 	unsigned long flags;
-	
+
 	sbmac_set_channel_state(sc,sbmac_state_off);
-	
+
 	del_timer_sync(&sc->sbm_timer);
-	
+
 	spin_lock_irqsave(&sc->sbm_lock, flags);
-	
+
 	netif_stop_queue(dev);
-	
+
 	if (debug > 1) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
 	}
-	
+
 	spin_unlock_irqrestore(&sc->sbm_lock, flags);
-	
-	/* Make sure there is no irq-handler running on a different CPU. */
+
 	synchronize_irq();
-	
 	free_irq(dev->irq, dev);
-	
+
 	sbdma_emptyring(&(sc->sbm_txdma));
 	sbdma_emptyring(&(sc->sbm_rxdma));
 	
 	MOD_DEC_USE_COUNT;
-	
+
 	return 0;
 }
 
@@ -2827,8 +2773,8 @@
 	port = A_MAC_CHANNEL_BASE(chan);
 	sbmac_parse_hwaddr(addr,eaddr);
 	val = sbmac_addr2reg(eaddr);
-	SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val);
-	val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+	SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR),val);
+	val = SBMAC_READCSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR));
 }
 #endif
 
@@ -2862,15 +2808,15 @@
 	 * Walk through the Ethernet controllers and find
 	 * those who have their MAC addresses set.
 	 */
-	chip_revision = SBMAC_READCSR(PKSEG1(A_SCD_SYSTEM_REVISION));
-	switch ((int)G_SYS_PART(chip_revision)) {
-	case 0x1150:
-	case 0x1250:
+	switch (soc_type) {
+	case K_SYS_SOC_TYPE_BCM1250:
+	case K_SYS_SOC_TYPE_BCM1250_ALT:
 		chip_max_units = 3;
 		break;
-	case 0x1120:
-	case 0x1125:
-	case 0x1126:
+	case K_SYS_SOC_TYPE_BCM1120:
+	case K_SYS_SOC_TYPE_BCM1125:
+	case K_SYS_SOC_TYPE_BCM1125H:
+	case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
 		chip_max_units = 2;
 		break;
 	default:
@@ -2894,9 +2840,10 @@
 		 * If we find a zero, skip this MAC.
 		 */
 
-		sbmac_orig_hwaddr[idx] = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+		sbmac_orig_hwaddr[idx] = SBMAC_READCSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR));
 		if (sbmac_orig_hwaddr[idx] == 0) {
-		    printk( KERN_DEBUG "sbmac: not configuring MAC at %x\n",(uint32_t)port);
+			printk(KERN_DEBUG "sbmac: not configuring MAC at "
+			       "%lx\n", port);
 		    continue;
 		}
 
@@ -2908,15 +2855,16 @@
 		if (!dev) 
 		  return -ENOMEM;	/* return ENOMEM */
 
+		printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
+
 		dev->irq = K_INT_MAC_0 + idx;
 		dev->base_addr = port;
 		dev->mem_end = 0;
 		/*dev->init = sbmac_init;*/
-		sbmac_init(dev);
+		sbmac_init(dev, macidx);
 
 		dev_sbmac[macidx] = dev;
 		macidx++;
-
 	}
 
 	/*
@@ -2935,7 +2883,8 @@
 	sbmac_port_t port;
 	for (idx = 0; idx < MAX_UNITS; idx++) {
 		dev = dev_sbmac[idx];
-		if (dev == NULL) continue;
+		if (dev == NULL)
+			continue;
 		if (dev->priv != NULL) {
 			struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
 			
@@ -2946,8 +2895,8 @@
 		}
 
 	        port = A_MAC_CHANNEL_BASE(idx);
-		SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] );
-		KFREE(dev);
+		SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] );
+		kfree(dev);
 		dev_sbmac[idx] = NULL;
 	}
 }
diff -urN linux-2.4.23-bk1/drivers/net/sgiseeq.c linux-2.4.23-bk2/drivers/net/sgiseeq.c
--- linux-2.4.23-bk1/drivers/net/sgiseeq.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.23-bk2/drivers/net/sgiseeq.c	2003-12-03 02:49:52.000000000 -0800
@@ -5,51 +5,45 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
+#include <linux/socket.h>
 #include <linux/in.h>
+#include <linux/route.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
 
+#include <asm/byteorder.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
-#include <linux/socket.h>
-#include <linux/route.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/sgi/sgihpc.h>
-#include <asm/sgi/sgint23.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
 #include <asm/sgialib.h>
 
 #include "sgiseeq.h"
 
-static char *version =
-	"sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
+static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
 
 static char *sgiseeqstr = "SGI Seeq8003";
 
-/* If you want speed, you do something silly, it always has worked
- * for me.  So, with that in mind, I've decided to make this driver
- * look completely like a stupid Lance from a driver architecture
- * perspective.  Only difference is that here our "ring buffer" looks
- * and acts like a real Lance one does but is layed out like how the
- * HPC DMA and the Seeq want it to.  You'd be surprised how a stupid
- * idea like this can pay off in performance, not to mention making
- * this driver 2,000 times easier to write. ;-)
+/*
+ * If you want speed, you do something silly, it always has worked for me.  So,
+ * with that in mind, I've decided to make this driver look completely like a
+ * stupid Lance from a driver architecture perspective.  Only difference is that
+ * here our "ring buffer" looks and acts like a real Lance one does but is
+ * layed out like how the HPC DMA and the Seeq want it to.  You'd be surprised
+ * how a stupid idea like this can pay off in performance, not to mention
+ * making this driver 2,000 times easier to write. ;-)
  */
 
 /* Tune these if we tend to run out often etc. */
@@ -79,9 +73,10 @@
 	signed int buf_vaddr;
 };
 
-/* Warning: This structure is layed out in a certain way because
- *          HPC dma descriptors must be 8-byte aligned.  So don't
- *          touch this without some care.
+/*
+ * Warning: This structure is layed out in a certain way because HPC dma
+ *          descriptors must be 8-byte aligned.  So don't touch this without
+ *          some care.
  */
 struct sgiseeq_init_block { /* Note the name ;-) */
 	/* Ptrs to the descriptors in KSEG1 uncached space. */
@@ -96,8 +91,8 @@
 struct sgiseeq_private {
 	volatile struct sgiseeq_init_block srings;
 	char *name;
-	volatile struct hpc3_ethregs *hregs;
-	volatile struct sgiseeq_regs *sregs;
+	struct hpc3_ethregs *hregs;
+	struct sgiseeq_regs *sregs;
 
 	/* Ring entry counters. */
 	unsigned int rx_new, tx_new;
@@ -108,17 +103,23 @@
 	unsigned char mode;
 
 	struct net_device_stats stats;
+
+	struct net_device *next_module;
+	spinlock_t tx_lock;
 };
 
-static inline void hpc3_eth_reset(volatile struct hpc3_ethregs *hregs)
+/* A list of all installed seeq devices, for removing the driver module. */
+static struct net_device *root_sgiseeq_dev;
+
+static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
 {
-	hregs->rx_reset = (HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ);
+	hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ;
 	udelay(20);
 	hregs->rx_reset = 0;
 }
 
-static inline void reset_hpc3_and_seeq(volatile struct hpc3_ethregs *hregs,
-				       volatile struct sgiseeq_regs *sregs)
+static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
+				       struct sgiseeq_regs *sregs)
 {
 	hregs->rx_ctrl = hregs->tx_ctrl = 0;
 	hpc3_eth_reset(hregs);
@@ -128,15 +129,15 @@
 		       SEEQ_RCMD_IDRIB | SEEQ_RCMD_ICRC)
 
 static inline void seeq_go(struct sgiseeq_private *sp,
-			   volatile struct hpc3_ethregs *hregs,
-			   volatile struct sgiseeq_regs *sregs)
+			   struct hpc3_ethregs *hregs,
+			   struct sgiseeq_regs *sregs)
 {
 	sregs->rstat = sp->mode | RSTAT_GO_BITS;
 	hregs->rx_ctrl = HPC3_ERXCTRL_ACTIVE;
 }
 
 static inline void seeq_load_eaddr(struct net_device *dev,
-				   volatile struct sgiseeq_regs *sregs)
+				   struct sgiseeq_regs *sregs)
 {
 	int i;
 
@@ -169,7 +170,7 @@
 
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
-		if(!ib->tx_desc[i].tdma.pbuf) {
+		if (!ib->tx_desc[i].tdma.pbuf) {
 			unsigned long buffer;
 
 			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
@@ -177,9 +178,8 @@
 				return -ENOMEM;
 			ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
 			ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer);
-//			flush_cache_all();
 		}
-		ib->tx_desc[i].tdma.cntinfo = (TCNTINFO_INIT);
+		ib->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
 	}
 
 	/* And now the rx ring. */
@@ -192,11 +192,10 @@
 				return -ENOMEM;
 			ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
 			ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer);
-//			flush_cache_all();
 		}
-		ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT);
+		ib->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
 	}
-	ib->rx_desc[i - 1].rdma.cntinfo |= (HPCDMA_EOR);
+	ib->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR;
 	return 0;
 }
 
@@ -209,10 +208,10 @@
 	static int once;
 	struct sgiseeq_rx_desc *r = gpriv->srings.rx_desc;
 	struct sgiseeq_tx_desc *t = gpriv->srings.tx_desc;
-	volatile struct hpc3_ethregs *hregs = gpriv->hregs;
+	struct hpc3_ethregs *hregs = gpriv->hregs;
 	int i;
 
-	if(once)
+	if (once)
 		return;
 	once++;
 	printk("RING DUMP:\n");
@@ -248,9 +247,9 @@
 #define RDMACFG_INIT    (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
 
 static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
-		      volatile struct sgiseeq_regs *sregs)
+		     struct sgiseeq_regs *sregs)
 {
-	volatile struct hpc3_ethregs *hregs = sp->hregs;
+	struct hpc3_ethregs *hregs = sp->hregs;
 	int err;
 
 	reset_hpc3_and_seeq(hregs, sregs);
@@ -260,11 +259,11 @@
 
 	/* Setup to field the proper interrupt types. */
 	if (sp->is_edlc) {
-		sregs->tstat = (TSTAT_INIT_EDLC);
+		sregs->tstat = TSTAT_INIT_EDLC;
 		sregs->rw.wregs.control = sp->control;
 		sregs->rw.wregs.frame_gap = 0;
 	} else {
-		sregs->tstat = (TSTAT_INIT_SEEQ);
+		sregs->tstat = TSTAT_INIT_SEEQ;
 	}
 
 	hregs->rx_dconfig |= RDMACFG_INIT;
@@ -291,8 +290,8 @@
 }
 
 static inline void rx_maybe_restart(struct sgiseeq_private *sp,
-				    volatile struct hpc3_ethregs *hregs,
-				    volatile struct sgiseeq_regs *sregs)
+				    struct hpc3_ethregs *hregs,
+				    struct sgiseeq_regs *sregs)
 {
 	if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) {
 		hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[sp->rx_new]);
@@ -305,8 +304,8 @@
 				(rd) = &(sp)->srings.rx_desc[(sp)->rx_new])
 
 static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp,
-			      volatile struct hpc3_ethregs *hregs,
-			      volatile struct sgiseeq_regs *sregs)
+			      struct hpc3_ethregs *hregs,
+			      struct sgiseeq_regs *sregs)
 {
 	struct sgiseeq_rx_desc *rd;
 	struct sk_buff *skb = 0;
@@ -317,7 +316,7 @@
 
 	/* Service every received packet. */
 	for_each_rx(rd, sp) {
-		len = (PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3);
+		len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3;
 		pkt_pointer = (unsigned char *)(long)rd->buf_vaddr;
 		pkt_status = pkt_pointer[len + 2];
 
@@ -338,7 +337,7 @@
 				sp->stats.rx_packets++;
 				sp->stats.rx_bytes += len;
 			} else {
-				printk ("%s: Memory squeeze, deferring packet.\n",
+				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
 				sp->stats.rx_dropped++;
 			}
@@ -347,7 +346,7 @@
 		}
 
 		/* Return the entry to the ring pool. */
-		rd->rdma.cntinfo = (RCNTINFO_INIT);
+		rd->rdma.cntinfo = RCNTINFO_INIT;
 		sp->rx_new = NEXT_RX(sp->rx_new);
 	}
 	sp->srings.rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR);
@@ -356,7 +355,7 @@
 }
 
 static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
-					     volatile struct sgiseeq_regs *sregs)
+					     struct sgiseeq_regs *sregs)
 {
 	if (sp->is_edlc) {
 		sregs->rw.wregs.control = sp->control & ~(SEEQ_CTRL_XCNT);
@@ -365,7 +364,7 @@
 }
 
 static inline void kick_tx(struct sgiseeq_tx_desc *td,
-			   volatile struct hpc3_ethregs *hregs)
+			   struct hpc3_ethregs *hregs)
 {
 	/* If the HPC aint doin nothin, and there are more packets
 	 * with ETXD cleared and XIU set we must make very certain
@@ -383,8 +382,8 @@
 }
 
 static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp,
-			      volatile struct hpc3_ethregs *hregs,
-			      volatile struct sgiseeq_regs *sregs)
+			      struct hpc3_ethregs *hregs,
+			      struct sgiseeq_regs *sregs)
 {
 	struct sgiseeq_tx_desc *td;
 	unsigned long status = hregs->tx_ctrl;
@@ -409,7 +408,7 @@
 		if (!(td->tdma.cntinfo & (HPCDMA_XIU)))
 			break;
 		if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {
-			if(!(status & HPC3_ETXCTRL_ACTIVE)) {
+			if (!(status & HPC3_ETXCTRL_ACTIVE)) {
 				hregs->tx_ndptr = PHYSADDR(td);
 				hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
 			}
@@ -426,8 +425,10 @@
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
-	volatile struct hpc3_ethregs *hregs = sp->hregs;
-	volatile struct sgiseeq_regs *sregs = sp->sregs;
+	struct hpc3_ethregs *hregs = sp->hregs;
+	struct sgiseeq_regs *sregs = sp->sregs;
+
+	spin_lock(&sp->tx_lock);
 
 	/* Ack the IRQ and set software state. */
 	hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
@@ -435,59 +436,47 @@
 	/* Always check for received packets. */
 	sgiseeq_rx(dev, sp, hregs, sregs);
 
-	/* Only check for tx acks iff we have something queued. */
+	/* Only check for tx acks if we have something queued. */
 	if (sp->tx_old != sp->tx_new)
 		sgiseeq_tx(dev, sp, hregs, sregs);
 
 	if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) {
 		netif_wake_queue(dev);
 	}
+	spin_unlock(&sp->tx_lock);
 }
 
 static int sgiseeq_open(struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;
-	volatile struct sgiseeq_regs *sregs = sp->sregs;
-	unsigned long flags;
-	int err;
-
-	__save_and_cli(flags);
+	struct sgiseeq_regs *sregs = sp->sregs;
 
-	err = -EAGAIN;
-	if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
-		printk("Seeq8003: Can't get irq %d\n", dev->irq);
-		goto out;
-	}
-	err = init_seeq(dev, sp, sregs);
+	int err = init_seeq(dev, sp, sregs);
 	if (err)
-		goto out;
+		return err;
 
 	netif_start_queue(dev);
 
-out:
-	__restore_flags(flags);
-	return err;
+	return 0;
 }
 
 static int sgiseeq_close(struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
-	volatile struct sgiseeq_regs *sregs = sp->sregs;
+	struct sgiseeq_regs *sregs = sp->sregs;
 
 	netif_stop_queue(dev);
 
 	/* Shutdown the Seeq. */
 	reset_hpc3_and_seeq(sp->hregs, sregs);
 
-	free_irq(dev->irq, dev);
-
 	return 0;
 }
 
 static inline int sgiseeq_reset(struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
-	volatile struct sgiseeq_regs *sregs = sp->sregs;
+	struct sgiseeq_regs *sregs = sp->sregs;
 	int err;
 
 	err = init_seeq(dev, sp, sregs);
@@ -509,12 +498,12 @@
 static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
-	volatile struct hpc3_ethregs *hregs = sp->hregs;
+	struct hpc3_ethregs *hregs = sp->hregs;
 	unsigned long flags;
 	struct sgiseeq_tx_desc *td;
 	int skblen, len, entry;
 
-	save_and_cli(flags);
+	spin_lock_irqsave(&sp->tx_lock, flags);
 
 	/* Setup... */
 	skblen = skb->len;
@@ -530,22 +519,22 @@
 	 * 2) Do no allow the HPC to look at a new descriptor until
 	 *    we have completely set up it's state.  This means, do
 	 *    not clear HPCDMA_EOX in the current last descritptor
-	 *    until the one we are adding looks consistant and could
+	 *    until the one we are adding looks consistent and could
 	 *    be processes right now.
 	 * 3) The tx interrupt code must notice when we've added a new
 	 *    entry and the HPC got to the end of the chain before we
 	 *    added this new entry and restarted it.
 	 */
 	memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
-	if(len != skblen)
+	if (len != skblen)
 		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
-	                   (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);
+	                   HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX;
 	if (sp->tx_old != sp->tx_new) {
 		struct sgiseeq_tx_desc *backend;
 
 		backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)];
-		backend->tdma.cntinfo &= ~(HPCDMA_EOX);
+		backend->tdma.cntinfo &= ~HPCDMA_EOX;
 	}
 	sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
 
@@ -558,14 +547,14 @@
 
 	if (!TX_BUFFS_AVAIL(sp))
 		netif_stop_queue(dev);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&sp->tx_lock, flags);
 
 	return 0;
 }
 
 static void timeout(struct net_device *dev)
 {
-	printk("%s: transmit timed out, resetting\n", dev->name);
+	printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
 	sgiseeq_reset(dev);
 
 	dev->trans_start = jiffies;
@@ -608,49 +597,56 @@
 	buf[i].rdma.pnext = PHYSADDR(&buf[0]);
 }
 
-static char onboard_eth_addr[6];
-
 #define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
 
-int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs,
-		 struct hpc3_ethregs *hregs, int irq)
+int sgiseeq_init(struct hpc3_regs* regs, int irq)
 {
-	static unsigned version_printed;
-	int i;
+	struct net_device *dev;
 	struct sgiseeq_private *sp;
+	int err, i;
 
-	dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL);
-	if (dev->priv == NULL)
-		return -ENOMEM;
-
-	if (!version_printed++)
-		printk(version);
-
-	printk("%s: SGI Seeq8003 ", dev->name);
+	dev = alloc_etherdev(0);
+	if (!dev) {
+		printk(KERN_ERR "Sgiseeq: Etherdev alloc failed, aborting.\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	/* Make private data page aligned */
+	sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); 	 
+	if (!sp) {
+		printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
+		printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq);
+		err = -EAGAIN;
+		goto err_out_free_page;
+	}
+
+#define EADDR_NVOFS     250
+	for (i = 0; i < 3; i++) {
+		unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",
-		       dev->dev_addr[i] = onboard_eth_addr[i],
-		       i == 5 ? ' ': ':');
-
-	printk("\n");
+		dev->dev_addr[2 * i]     = tmp >> 8;
+		dev->dev_addr[2 * i + 1] = tmp & 0xff;
+	}
 
-	sp = (struct sgiseeq_private *) dev->priv;
 #ifdef DEBUG
 	gpriv = sp;
 	gdev = dev;
 #endif
-	memset((char *)dev->priv, 0, sizeof(struct sgiseeq_private));
-	sp->sregs = sregs;
-	sp->hregs = hregs;
+	sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
+	sp->hregs = &hpc3c0->ethregs;
 	sp->name = sgiseeqstr;
 
 	sp->srings.rx_desc = (struct sgiseeq_rx_desc *)
-	                     (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])));
+	                     KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]));
 	dma_cache_wback_inv((unsigned long)&sp->srings.rxvector,
 	                    sizeof(sp->srings.rxvector));
 	sp->srings.tx_desc = (struct sgiseeq_tx_desc *)
-	                     (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])));
+	                     KSEG1ADDR(ALIGNED(&sp->srings.txvector[0]));
 	dma_cache_wback_inv((unsigned long)&sp->srings.txvector,
 	                    sizeof(sp->srings.txvector));
 
@@ -659,71 +655,78 @@
 	setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS);
 
 	/* Reset the chip. */
-	hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs);
+	hpc3_eth_reset(sp->hregs);
 
-	sp->is_edlc = !(sregs->rw.rregs.collision_tx[0] & 0xff);
-	if (sp->is_edlc) {
-		sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |
-			       SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |
-			       SEEQ_CTRL_ENCARR);
+	sp->is_edlc = !(sp->sregs->rw.rregs.collision_tx[0] & 0xff);
+	if (sp->is_edlc)
+		sp->control = SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |
+			      SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |
+			      SEEQ_CTRL_ENCARR;
+
+	dev->open		= sgiseeq_open;
+	dev->stop		= sgiseeq_close;
+	dev->hard_start_xmit	= sgiseeq_start_xmit;
+	dev->tx_timeout		= timeout;
+	dev->watchdog_timeo	= (200 * HZ) / 1000;
+	dev->get_stats		= sgiseeq_get_stats;
+	dev->set_multicast_list	= sgiseeq_set_multicast;
+	dev->irq		= irq;
+	dev->dma		= 0;
+	dev->priv		= sp;
+
+	if (register_netdev(dev)) {
+		printk(KERN_ERR "Sgiseeq: Cannot register net device, "
+		       "aborting.\n");
+		err = -ENODEV;
+		goto err_out_free_irq;
 	}
 
-	dev->open                 = sgiseeq_open;
-	dev->stop                 = sgiseeq_close;
-	dev->hard_start_xmit      = sgiseeq_start_xmit;
-	dev->tx_timeout           = timeout;
-	dev->watchdog_timeo       = (200 * HZ) / 1000;
-	dev->get_stats            = sgiseeq_get_stats;
-	dev->set_multicast_list   = sgiseeq_set_multicast;
-	dev->irq                  = irq;
-	dev->dma                  = 0;
-	ether_setup(dev);
+	printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+	sp->next_module = root_sgiseeq_dev;
+	root_sgiseeq_dev = dev;
 
 	return 0;
-}
 
-static inline unsigned char str2hexnum(unsigned char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	return 0; /* foo */
+err_out_free_irq:
+	free_irq(irq, dev);
+err_out_free_page:
+	free_page((unsigned long) sp);
+err_out_free_dev:
+	kfree(dev);
+
+err_out:
+	return err;
 }
 
-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+static int __init sgiseeq_probe(void)
 {
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		unsigned char num;
+	printk(version);
 
-		if(*str == ':')
-			str++;
-		num = str2hexnum(*str++) << 4;
-		num |= (str2hexnum(*str++));
-		ea[i] = num;
-	}
+	/* On board adapter on 1st HPC is always present */
+	return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
 }
 
-int sgiseeq_probe(struct net_device *dev)
+static void __exit sgiseeq_exit(void)
 {
-	static int initialized;
-	char *ep;
-
-	if (initialized)	/* Already initialized? */
-		return 1;
-	initialized++;
+	struct net_device *next, *dev;
+	struct sgiseeq_private *sp;
+	int irq;
 
-	/* First get the ethernet address of the onboard interface from ARCS.
-	 * This is fragile; PROM doesn't like running from cache.
-	 * On MIPS64 it crashes for some other, yet unknown reason ...
-	 */
-	ep = ArcGetEnvironmentVariable("eaddr");
-	str2eaddr(onboard_eth_addr, ep);
-	return sgiseeq_init(dev,
-			    (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),
-			    &hpc3c0->ethregs, SGI_ENET_IRQ);
+	for (dev = root_sgiseeq_dev; dev; dev = next) {
+		sp = (struct sgiseeq_private *) dev->priv;
+		next = sp->next_module;
+		irq = dev->irq;
+		unregister_netdev(dev);
+		free_irq(irq, dev);
+		free_page((unsigned long) dev->priv);
+		kfree(dev);
+	}
 }
 
+module_init(sgiseeq_probe);
+module_exit(sgiseeq_exit);
+
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.23-bk1/drivers/pcmcia/Config.in linux-2.4.23-bk2/drivers/pcmcia/Config.in
--- linux-2.4.23-bk1/drivers/pcmcia/Config.in	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.23-bk2/drivers/pcmcia/Config.in	2003-12-03 02:49:52.000000000 -0800
@@ -29,5 +29,20 @@
    if [ "$CONFIG_8xx" = "y" ]; then
       dep_tristate '  M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
    fi
+   if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+      dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA 
+      if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
+        bool '  Pb1x00 board support' CONFIG_PCMCIA_PB1X00
+        bool '  Db1x00 board support' CONFIG_PCMCIA_DB1X00
+        bool '  XXS1500 board support' CONFIG_PCMCIA_XXS1500
+      fi
+   fi
+   if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+      dep_bool '  SiByte PCMCIA support' CONFIG_PCMCIA_SIBYTE $CONFIG_PCMCIA $CONFIG_BLK_DEV_IDE_SIBYTE
+   fi
+   if [ "$CONFIG_VRC4173" = "y" -o "$CONFIG_VRC4173" = "m" ]; then
+      dep_tristate '  NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA
+   fi
 fi
+
 endmenu
diff -urN linux-2.4.23-bk1/drivers/pcmcia/Makefile linux-2.4.23-bk2/drivers/pcmcia/Makefile
--- linux-2.4.23-bk1/drivers/pcmcia/Makefile	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.23-bk2/drivers/pcmcia/Makefile	2003-12-03 02:49:52.000000000 -0800
@@ -59,8 +59,15 @@
   endif
 endif
 
+obj-$(CONFIG_PCMCIA_AU1X00)			+= au1x00_ss.o
+au1000_ss-objs-y				:= au1000_generic.o
+au1000_ss-objs-$(CONFIG_PCMCIA_PB1X00)		+= au1000_pb1x00.o
+au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00)		+= au1000_db1x00.o
+au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500) 	+= au1000_xxs1500.o
+
 obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
 obj-$(CONFIG_PCMCIA_M8XX)	+= m8xx_pcmcia.o
+obj-$(CONFIG_PCMCIA_SIBYTE)	+= sibyte_generic.o
 
 sa1100_cs-objs-y				:= sa1100_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
@@ -82,6 +89,8 @@
 sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
 
+obj-$(CONFIG_PCMCIA_VRC4173)	+= vrc4173_cardu.o
+
 include $(TOPDIR)/Rules.make
 
 pcmcia_core.o:  $(pcmcia_core-objs)
@@ -90,5 +99,8 @@
 sa1100_cs.o: $(sa1100_cs-objs-y)
 	$(LD) -r -o $@ $(sa1100_cs-objs-y)
 
+au1x00_ss.o: $(au1000_ss-objs-y)
+	$(LD) -r -o $@ $(au1000_ss-objs-y)
+
 yenta_socket.o: $(yenta_socket-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
diff -urN linux-2.4.23-bk1/drivers/pcmcia/sibyte_generic.c linux-2.4.23-bk2/drivers/pcmcia/sibyte_generic.c
--- linux-2.4.23-bk1/drivers/pcmcia/sibyte_generic.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/drivers/pcmcia/sibyte_generic.c	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2003 Broadcom Corporation
+ *    originally contributed to SiByte, Inc as
+ *    "sb1250pc.c 0.10 (Stanley Chen & James Liao)"
+ *
+ * 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.
+ */
+
+/*
+ * Notes / Apologies:
+ *   - only ATA cards tested so far
+ *   - requires hack in cs.c to avoid poking the CISCOR register
+ *   - ack_intr routine might be improved to avoid error msgs.
+ *   - remove and re-insert doesn't work (crash or fail to probe drive)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/timer.h>
+#include <linux/ide.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cs.h>
+#include "cs_internal.h"
+
+#include <asm/io.h>
+
+#include <asm/sibyte/board.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/64bit.h>
+
+#define PFX "sibyte-pcmcia: "
+
+MODULE_AUTHOR("Kip Walker, Stanley Chen & James Liao");
+MODULE_DESCRIPTION("SiByte PCMCIA socket driver");
+
+#undef PCMCIA_DEBUG
+#ifdef PCMCIA_DEBUG
+#define DPRINTK(args...) do { printk(KERN_DEBUG args); } while (0)
+#else
+#define DPRINTK(n, args...) do { } while (0)
+#endif
+
+static unsigned long sb_pcmcia_base = PCMCIA_PHYS;
+static unsigned long sb_pcmcia_size;
+#define SIBYTE_CS_REG(pcaddr)  (IO_SPACE_BASE + sb_pcmcia_base - mips_io_port_base + pcaddr)
+#define SB_PC_PORT 0xff00
+extern void sibyte_set_ideops(ide_hwif_t *hwif);
+
+/* The card status change interrupt */
+static int cs_irq = K_INT_PCMCIA;
+
+/* Memory map windows */
+static struct pccard_mem_map sibyte_memmap[MAX_WIN];
+static struct pccard_io_map  sibyte_iomap[MAX_IO_WIN];
+
+/*====================================================================*/
+/* Socket structures                                                  */
+/*====================================================================*/
+
+
+static void sb1250pc_interrupt(int irq, void *dev, struct pt_regs *regs);
+static struct pccard_operations sb1250pc_operations;
+
+typedef struct socket_handler_t {
+	void	(*handler)(void *info, u_int events);
+	void	*info;
+} socket_handler_t;
+
+static socket_handler_t socket_handler;
+
+/*
+ * cap features:
+ *   full 32-bit addressing for 16-bit PCcard memory windows
+ *   16-bit card memory and IO accesses need bus_ops
+ *   only 16-bit PCcards
+ *   align memory windows
+ *   statically mapped memory windows
+ */
+static socket_cap_t sb1250pc_cap = {
+	features: (SS_CAP_PAGE_REGS |
+//		   SS_CAP_VIRTUAL_BUS |
+		   SS_CAP_PCCARD |
+		   SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP),
+	irq_mask:  0,		/* tell ide layer to take PCI irq */
+	map_size:  0x4000000,	/* 64MB minimum window size (What *should* this be?)*/
+	io_offset: SB_PC_PORT,	/* This is ide5 -- just a special token for ide-sibyte */
+	pci_irq:   K_INT_PC_READY, /* XXXKW This serves as IREQ# for CompactFlash */
+	cb_dev:    NULL,
+	bus:       NULL
+};
+
+/*====================================================================*/
+/* Useful macros                                                      */
+/*====================================================================*/
+
+#define READ_PHYSADDR(addr) (*(volatile u32 *)(KSEG1ADDR(addr)))
+#define WRITE_PHYSADDR(addr, data) (*(volatile u32 *)(KSEG1ADDR(addr))) = (data)
+
+#define READ_CSR32(reg)		csr_in32(IO_SPACE_BASE + (reg))
+#define WRITE_CSR32(data, reg)	csr_out32(data, IO_SPACE_BASE + (reg))
+
+#define sb1250pc_write_config(data)	WRITE_CSR32(data, A_IO_PCMCIA_CFG)
+#define sb1250pc_read_config()		READ_CSR32(A_IO_PCMCIA_CFG)
+#define sb1250pc_read_status()		READ_CSR32(A_IO_PCMCIA_STATUS)
+
+#define CARDPRESENT(s) (((s) & (M_PCMCIA_STATUS_CD1 | M_PCMCIA_STATUS_CD2)) == 0)
+
+int sb_pcmcia_ack_intr(struct hwif_s *hwif)
+{
+	/*
+	 * XXXKW verify interrupt and return appropriate value?
+	 * Simple check of the bit in A_GPIO_READ didn't DTRT
+	 */
+
+	/* Clear out the GPIO edge detector */
+	WRITE_CSR32(1 << K_GPIO_PC_READY, A_GPIO_CLR_EDGE);
+	return 1;
+}
+
+/*====================================================================*/
+/* Interrupt handling                                                 */
+/*====================================================================*/
+
+static unsigned int pending_events;
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static void sb1250pc_bh(void *dummy)
+{
+	unsigned int events;
+
+	spin_lock_irq(&pending_event_lock);
+	events = pending_events;
+	pending_events = 0;
+	spin_unlock_irq(&pending_event_lock);
+
+	if (socket_handler.handler)
+		socket_handler.handler(socket_handler.info, events);
+}
+
+static struct tq_struct sb1250pc_task =
+{
+	routine:	sb1250pc_bh
+};
+
+static void sb1250pc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	unsigned int events = 0;
+	uint32_t status;
+
+	status = sb1250pc_read_status();
+
+	if (status & M_PCMCIA_STATUS_CDCHG) {
+		events = SS_DETECT;
+		if (CARDPRESENT(status)) {
+			events |= SS_INSERTION;
+		} else {
+			events |= SS_EJECTION;
+		}
+	}
+#if 0
+	/* XXXKW ignore everything but CD? */
+	if (status & M_PCMCIA_STATUS_RDYCHG) {
+		if (status & M_PCMCIA_STATUS_RDY) {
+			/* XXXKW if ide, ack the interrupt? */
+			events |= SS_READY;
+		}
+	}
+#endif
+
+	if (events) {
+		DPRINTK(PFX " passing %x to bh\n", events);
+
+		/* Pass the events off to the bottom-half */
+		spin_lock(&pending_event_lock);
+		pending_events |= events;
+		spin_unlock(&pending_event_lock);
+		schedule_task(&sb1250pc_task);
+	}
+}
+
+/*====================================================================*/
+/* PC Card Operations                                                 */
+/*====================================================================*/
+
+static int sb1250pc_register_callback(unsigned int lsock,
+				      void (*handler)(void *, unsigned int),
+				      void * info)
+{
+	DPRINTK(PFX "sb1250pc_register_callback(%d)\n", lsock);
+
+	socket_handler.handler = handler;
+	socket_handler.info = info;
+	if (handler == NULL) {
+		MOD_DEC_USE_COUNT;
+	} else {
+		MOD_INC_USE_COUNT;
+	}
+	return 0;
+}
+
+/*====================================================================*/
+
+static int sb1250pc_get_status(unsigned int lsock, u_int *value)
+{
+	u_int val;
+	uint32_t status;
+#if PCMCIA_DEBUG
+	u32 config;
+#endif
+
+	status = sb1250pc_read_status();
+#if PCMCIA_DEBUG
+	config = sb1250pc_read_config();
+#endif
+
+	val = CARDPRESENT(status) ? SS_DETECT : 0;
+	val |= (status & M_PCMCIA_CFG_RESET) ? SS_RESET : 0;
+	val |= (status & (M_PCMCIA_STATUS_3VEN | M_PCMCIA_STATUS_5VEN)) ?
+		SS_POWERON : 0;
+	val |= (status & M_PCMCIA_STATUS_RDY) ? SS_READY : 0;
+	val |= (status & M_PCMCIA_STATUS_WP) ? SS_WRPROT : 0;
+	val |= ((status & M_PCMCIA_STATUS_VS2) &&
+		(~status & M_PCMCIA_STATUS_VS1)) ? SS_3VCARD : 0;
+	val |= (status & (M_PCMCIA_STATUS_CDCHG | M_PCMCIA_STATUS_WPCHG
+			  | M_PCMCIA_STATUS_RDYCHG)) ? SS_STSCHG : 0;
+	/* XXXKW SS_INSERTION on cdchange? */
+
+	DPRINTK(PFX "GetStatus(%d) = %x", lsock, val);
+#if PCMCIA_DEBUG
+	DPRINTK(" [config(0x%4.4x) status(0x%4.4x)]", config, status);
+#endif
+	DPRINTK("\n");
+
+	*value = val;
+	return 0;
+}
+
+/*====================================================================*/
+
+static int sb1250pc_inquire_socket(unsigned int lsock, socket_cap_t *cap)
+{
+	*cap = sb1250pc_cap;
+
+	DPRINTK(PFX "InquireSocket(%d) = features 0x%4.4x, irq_mask "
+	       "0x%4.4x, map_size 0x%4.4x\n", lsock, cap->features,
+	       cap->irq_mask, cap->map_size);
+
+	return 0;
+}
+
+/*====================================================================*/
+
+// This garbage function never seems to get called...
+static int sb1250pc_get_socket(unsigned int lsock, socket_state_t *state)
+{
+	DPRINTK(PFX "Does GetSocket(%d) ever get called???", lsock);
+	return -1;
+} /* sb1250pc_get_socket */
+
+/*====================================================================*/
+
+static uint32_t sibyte_set_power(uint32_t config, int vcc)
+{
+	config &= ~(M_PCMCIA_CFG_3VEN | M_PCMCIA_CFG_5VEN);
+	if (vcc == 33) {
+		config |= M_PCMCIA_CFG_3VEN;
+	} else if (vcc == 50) {
+		config |= M_PCMCIA_CFG_5VEN;
+	}
+
+	sb1250pc_write_config(config);
+	return config;
+}
+
+static int sb1250pc_set_socket(unsigned int lsock, socket_state_t *state)
+{
+	uint32_t config;
+
+	DPRINTK(PFX "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	       "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+	       state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+	config = sb1250pc_read_config();
+
+	config = sibyte_set_power(config, state->Vcc);
+
+	if (state->flags & SS_DEBOUNCED)
+		state->flags &= ~SS_DEBOUNCED; /* SS_DEBOUNCED is oneshot */
+	/* XXXKW SS_OUTPUT_ENA? */
+	/* XXXKW SS_PWR_AUTO? */
+	/* XXXKW SS_IOCARD? */
+
+	if (state->csc_mask & SS_DETECT)
+		config &= ~M_PCMCIA_CFG_CDMASK;
+	else
+		config |= M_PCMCIA_CFG_CDMASK;
+
+	config &= ~M_PCMCIA_CFG_RESET;
+	if (state->flags & SS_RESET) {
+		DPRINTK(PFX "  resetting PCMCIA\n");
+		config |= M_PCMCIA_CFG_RESET;
+	}
+	sb1250pc_write_config(config);
+
+	DPRINTK(PFX "  new config: %x\n", sb1250pc_read_config());
+
+	return 0;
+}
+
+/*====================================================================*/
+
+static int sb1250pc_get_io_map(unsigned int lsock, struct pccard_io_map *io)
+{
+	*io = sibyte_iomap[io->map];
+
+	DPRINTK(PFX "GetIOMap(%d, %d) = %#2.2x, %d ns, "
+	       "%#4.4x-%#4.4x\n", lsock, io->map, io->flags,
+	       io->speed, io->start, io->stop);
+	return 0;
+} /* sb1250pc_get_io_map */
+
+static int sb1250pc_set_io_map(unsigned int lsock, struct pccard_io_map *io)
+{
+   	unsigned int speed;
+	unsigned long start;
+	u32 config;
+
+	/* SB1250 uses direct mapping */
+	DPRINTK(PFX "SetIOMap(%d, %d, %#2.2x, %d ns, "
+	       "%#4.4x-%#4.4x) called\n", lsock, io->map, io->flags,
+	       io->speed, io->start, io->stop);
+
+	if (io->map >= MAX_IO_WIN) {
+		DPRINTK(KERN_ERR PFX "map (%d) out of range\n", io->map);
+		return -1;
+	}
+
+	if (io->flags & MAP_ACTIVE) {
+		speed = (io->speed > 0) ? io->speed : 255;
+	}
+
+	config = sb1250pc_read_config();
+
+	if (io->flags & MAP_ATTRIB) {
+		DPRINTK(PFX "  Setting pcmcia_cfg_reg to 1  (Attribute Mode)\n");
+		config |= M_PCMCIA_CFG_ATTRMEM;
+	} else {
+		DPRINTK(PFX "  Setting pcmcia_cfg_reg to 0  (Data Mode)\n");
+		config &= ~M_PCMCIA_CFG_ATTRMEM;
+	}
+	sb1250pc_write_config(config);
+
+	start = io->start;
+
+	if (io->stop == 1) {
+		io->stop = PAGE_SIZE - 1;
+	}
+
+	if (io->start == 0)
+		io->start = sb_pcmcia_base;
+
+	io->stop = io->start + (io->stop - start);
+
+	sibyte_iomap[io->map] = *io;
+
+	DPRINTK(PFX "SetIOMap(%d, %d, %#2.2x, %d ns, "
+	       "%#4.4x-%#4.4x) returns\n", lsock, io->map, io->flags,
+	       io->speed, io->start, io->stop);
+	return 0;
+} /* sb1250pc_set_io_map */
+
+/*====================================================================*/
+
+static int sb1250pc_get_mem_map(unsigned int lsock, struct pccard_mem_map *mem)
+{
+	if(mem->map >= MAX_WIN)
+		return -EINVAL;
+	
+	*mem = sibyte_memmap[mem->map];
+
+	DPRINTK(PFX "GetMemMap(%d, mem[%d, %#2.2x, %d ns, "
+	       "%#5.5lx-%#5.5lx, %#5.5x) called\n", lsock, mem->map, mem->flags,
+	       mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+
+	return 0;
+}
+
+static int sb1250pc_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem)
+{
+	u32 old_config, new_config;
+
+	if (mem->map >= MAX_WIN) {
+		DPRINTK(KERN_ERR PFX "map (%d) out of range\n", mem->map);
+		return -1;
+	}
+
+	if (mem->sys_start == 0)
+		mem->sys_start = mem->card_start + sb_pcmcia_base;
+
+	if (mem->sys_stop == 0)
+		mem->sys_stop = mem->sys_start + sb_pcmcia_size - 1;
+
+	old_config = sb1250pc_read_config();
+
+	DPRINTK(PFX "  Setting mem_map %p\n", mem);
+	if (mem->flags & MAP_ATTRIB) {
+		DPRINTK(PFX "  Setting pcmcia_cfg_reg to 1 (Attribute Mode)\n");
+		new_config = old_config | M_PCMCIA_CFG_ATTRMEM;
+	} else {
+		DPRINTK(PFX "  Setting pcmcia_cfg_reg to 0 (Data Mode)\n");
+		new_config = old_config & ~M_PCMCIA_CFG_ATTRMEM;
+	}
+	if (new_config != old_config)
+		sb1250pc_write_config(new_config);
+
+	sibyte_memmap[mem->map] = *mem;
+
+	DPRINTK(PFX "SetMemMap(%d, mem[%d, %#2.2x, %d ns], "
+	       "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+	       mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+
+	return 0;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_PROC_FS
+/* sb1250pc_proc_status()
+ * Implements the /proc/bus/pccard/??/status file.
+ *
+ * Returns: the number of characters added to the buffer
+ *
+ * Be aware that reading status clears the "change" bits; this seems
+ * unlikely to bite us by making us miss interrupts.
+ */
+static int sb1250pc_proc_status(char *buf, char **start, off_t pos,
+				int count, int *eof, void *data)
+{
+	char *p = buf;
+	u32 addr, temp;
+	u32 status, config;
+	//unsigned int sock = (unsigned int) data;
+
+	config = sb1250pc_read_config();
+	status = sb1250pc_read_status();
+	p += sprintf(p, "config(0x%4.4x) status(0x%4.4x)\n", config, status);
+
+	for (addr = sb_pcmcia_base; addr < sb_pcmcia_base + 8; addr+=4) {
+		temp = READ_PHYSADDR(addr);
+		p += sprintf(p, " Looking up addr 0x%x: 0x%8.8x\n", addr, temp);
+	}
+
+	return p - buf;
+}
+
+static void sb1250pc_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+	struct proc_dir_entry *entry;
+	
+	if ((entry = create_proc_entry("sb1250pc", 0, base)) == NULL) {
+		printk(KERN_ERR PFX "Unable to install \"sb1250pc\" procfs entry\n");
+		return;
+	} else
+		printk(KERN_INFO PFX "Setting up \"sb1250pc\" procfs entry\n");
+	
+	entry->read_proc = sb1250pc_proc_status;
+	entry->data = (void *) sock;
+}
+
+#endif
+
+/*====================================================================*/
+
+static int sibyte_pcmcia_initted = 0;
+
+static int sb1250pc_init(unsigned int s)
+{
+	u32 config, status;
+	
+	DPRINTK(PFX "Initializing SB1250 PCMCIA:\n");
+
+	/* Read status to clear interrupt sources */
+	status = sb1250pc_read_status();
+
+	/*
+	 * Before getting setting up the IRQ, set the config:
+	 *   reset off, auto-power off
+	 *   interrupt mask: WP, CD, Ready off
+	 */
+	config = sb1250pc_read_config();
+	config = M_PCMCIA_CFG_CDMASK | M_PCMCIA_CFG_WPMASK | M_PCMCIA_CFG_RDYMASK;
+	sb1250pc_write_config(config);
+	   
+	if (!sibyte_pcmcia_initted) {
+		uint32_t gpio_ctrl;
+		/* Set up the GPIO for PC_READY for use in ide-cs */
+		gpio_ctrl = READ_CSR32(A_GPIO_INT_TYPE);
+		gpio_ctrl &= ~M_GPIO_INTR_TYPEX(K_GPIO_PC_READY);
+		gpio_ctrl |= V_GPIO_INTR_TYPEX(K_GPIO_PC_READY, K_GPIO_INTR_EDGE);
+		WRITE_CSR32(gpio_ctrl, A_GPIO_INT_TYPE);
+		WRITE_CSR32(1 << K_GPIO_PC_READY, A_GPIO_CLR_EDGE);
+
+		/* Invert to get busy->ready transition */
+		gpio_ctrl = READ_CSR32(A_GPIO_INPUT_INVERT);
+		gpio_ctrl |= 1 << K_GPIO_PC_READY;
+		WRITE_CSR32(gpio_ctrl, A_GPIO_INPUT_INVERT);
+
+		/* Should not be any pending since we masked all sources */
+		if (request_irq(cs_irq, sb1250pc_interrupt, 0, "pcmcia", NULL))
+			return -ENODEV;
+		DPRINTK(PFX "  IRQ %d registered\n", cs_irq);
+
+		sibyte_pcmcia_initted = 1;
+	}
+	
+	status = sb1250pc_read_status();
+	DPRINTK(PFX "  config(0x%4.4x) status(0x%4.4x)\n", config, status);
+
+	sb1250pc_set_socket(s, &dead_socket);
+
+	return 0;
+}
+
+static int sb1250pc_suspend(unsigned int sock)
+{
+	free_irq(cs_irq, NULL);
+	DPRINTK(KERN_INFO PFX "  IRQ %d freed\n", cs_irq);
+	return sb1250pc_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations sb1250pc_operations = {
+	sb1250pc_init,
+	sb1250pc_suspend,
+	sb1250pc_register_callback,
+	sb1250pc_inquire_socket,
+	sb1250pc_get_status,
+	sb1250pc_get_socket,
+	sb1250pc_set_socket,
+	sb1250pc_get_io_map,
+	sb1250pc_set_io_map,
+	sb1250pc_get_mem_map,
+	sb1250pc_set_mem_map,
+#ifdef CONFIG_PROC_FS
+	sb1250pc_proc_setup
+#endif
+};
+
+/*
+ * XXXKW This is a hack.  The ide-cs stuff seems to leave us in
+ * Attribute mode.  Since I know that a SELECT_DRIVE will happen as
+ * the first I/O access, use this opportunity to enter data mode.
+ */
+static void sibyte_pcmcia_selectproc(ide_drive_t *drive)
+{
+	sb1250pc_write_config(sb1250pc_read_config() & ~M_PCMCIA_CFG_ATTRMEM);
+}
+
+static int sibyte_pc_prep_ide(void)
+{
+	int i;
+	ide_hwif_t *hwif = NULL;
+
+	/* Stake early claim on an ide_hwif */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			hwif = &ide_hwifs[i];
+			break;
+		}
+	}
+	if (hwif == NULL) {
+		printk("No space for SiByte onboard PCMCIA driver in ide_hwifs[].  Not enabled.\n");
+		return 1;
+	}
+
+	/*
+	 * Prime the hwif with port values, so when a card is
+	 * detected, the 'io_offset' from the capabilities will lead
+	 * it here
+	 */
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_CS_REG(0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_CS_REG(1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_CS_REG(2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_CS_REG(3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_CS_REG(4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_CS_REG(5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_CS_REG(6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_CS_REG(7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_CS_REG(6); /* XXXKW ? */
+	hwif->hw.ack_intr                     = sb_pcmcia_ack_intr;
+	hwif->selectproc                      = sibyte_pcmcia_selectproc;
+	hwif->hold                            = 1;
+	hwif->mmio                            = 2;
+	sibyte_set_ideops(&ide_hwifs[i]);
+
+	printk("SiByte onboard PCMCIA-IDE configured as device %i\n", i);
+
+	return 0;
+}
+
+static int __init sibyte_pcmcia_init(void)
+{
+	servinfo_t info;
+	u32 addr, temp;
+	u64 cfg;
+
+	CardServices(GetCardServicesInfo, &info);
+	if (info.Revision != CS_RELEASE_CODE) {
+		printk(KERN_ERR PFX "Card Services release does not match!\n");
+		return -1;
+	}
+
+        cfg = in64(IO_SPACE_BASE + A_SCD_SYSTEM_CFG);
+        if (!(cfg & M_SYS_PCMCIA_ENABLE)) {
+		printk(KERN_INFO PFX "chip not configured for PCMCIA\n");
+		return -1;
+	}
+
+	/* Find memory base address and size */
+	addr = A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, PCMCIA_CS));
+	temp = G_IO_MULT_SIZE(csr_in32(IO_SPACE_BASE + addr));
+	printk(PFX "Looking up addr 0x%x: 0x%4.4x (IO size)\n", addr, temp);
+	sb_pcmcia_size = (temp+1) << S_IO_REGSIZE;
+
+	addr = A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, PCMCIA_CS));
+	temp = G_IO_START_ADDR(csr_in32(KSEG1|addr));
+	printk(PFX "Looking up addr 0x%x: 0x%4.4x (IO Base Address)\n", addr, temp);
+	if (temp << S_IO_ADDRBASE != PCMCIA_PHYS)
+		panic(PFX "pcmcia base doesn't match gencs value\n");
+
+	/* check and request memory region */
+	if (check_mem_region(sb_pcmcia_base, sb_pcmcia_size)) {
+		printk(KERN_ERR PFX "Can't request memory region?\n");
+	} else {
+		request_mem_region(sb_pcmcia_base, sb_pcmcia_size, "sibyte-pcmcia");
+		printk(PFX "Memory region 0x%8.8lx of size 0x%8.8lx requested.\n",
+		       sb_pcmcia_base, sb_pcmcia_size);
+	}
+
+	/* register with socket services */
+	if (register_ss_entry(1, &sb1250pc_operations)) {
+		printk(KERN_ERR PFX "register_ss_entry() failed\n");
+		release_region(sb_pcmcia_base, sb_pcmcia_size);
+		return -ENODEV;
+	}
+
+	if (!sibyte_pc_prep_ide()) {
+		/* XXXKW hack for ide-cs warning squash */
+		request_region(sb1250pc_cap.io_offset, 16, "ide-cs");
+		request_mem_region(SIBYTE_CS_REG(0), 8, "sibyte-ide-cs");
+	}
+
+	return 0;
+}
+
+static void __exit sibyte_pcmcia_exit(void)
+{
+	/* XXXKW untested as module */
+	unregister_ss_entry(&sb1250pc_operations);
+	release_region(sb_pcmcia_base, sb_pcmcia_size);
+}
+
+module_init(sibyte_pcmcia_init);
+module_exit(sibyte_pcmcia_exit);
diff -urN linux-2.4.23-bk1/drivers/pcmcia/vrc4173_cardu.c linux-2.4.23-bk2/drivers/pcmcia/vrc4173_cardu.c
--- linux-2.4.23-bk1/drivers/pcmcia/vrc4173_cardu.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/drivers/pcmcia/vrc4173_cardu.c	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,628 @@
+/*
+ * FILE NAME
+ *	drivers/pcmcia/vrc4173_cardu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * 	NEC VRC4173 CARDU driver for Socket Services
+ *	(This device doesn't support CardBus. it is supporting only 16bit PC Card.)
+ *
+ * Copyright 2002,2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ *  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 SOFTWARE IS PROVIDED ``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.
+ *
+ *  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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+
+#include "vrc4173_cardu.h"
+
+MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
+MODULE_LICENSE("GPL");
+
+static int vrc4173_cardu_slots;
+
+static vrc4173_socket_t cardu_sockets[CARDU_MAX_SOCKETS];
+
+extern struct socket_info_t *pcmcia_register_socket (int slot,
+                                                     struct pccard_operations *vtable,
+                                                     int use_bus_pm);
+extern void pcmcia_unregister_socket(struct socket_info_t *s);
+
+static inline uint8_t exca_readb(vrc4173_socket_t *socket, uint16_t offset)
+{
+	return readb(socket->base + EXCA_REGS_BASE + offset);
+}
+
+static inline uint16_t exca_readw(vrc4173_socket_t *socket, uint16_t offset)
+{
+	uint16_t val;
+
+	val = readb(socket->base + EXCA_REGS_BASE + offset);
+	val |= (u16)readb(socket->base + EXCA_REGS_BASE + offset + 1) << 8;
+
+	return val;
+}
+
+static inline void exca_writeb(vrc4173_socket_t *socket, uint16_t offset, uint8_t val)
+{
+	writeb(val, socket->base + EXCA_REGS_BASE + offset);
+}
+
+static inline void exca_writew(vrc4173_socket_t *socket, uint8_t offset, uint16_t val)
+{
+	writeb((u8)val, socket->base + EXCA_REGS_BASE + offset);
+	writeb((u8)(val >> 8), socket->base + EXCA_REGS_BASE + offset + 1);
+}
+
+static inline uint32_t cardbus_socket_readl(vrc4173_socket_t *socket, u16 offset)
+{
+	return readl(socket->base + CARDBUS_SOCKET_REGS_BASE + offset);
+}
+
+static inline void cardbus_socket_writel(vrc4173_socket_t *socket, u16 offset, uint32_t val)
+{
+	writel(val, socket->base + CARDBUS_SOCKET_REGS_BASE + offset);
+}
+
+static void cardu_pciregs_init(struct pci_dev *dev)
+{
+	u32 syscnt;
+	u16 brgcnt;
+	u8 devcnt;
+
+	pci_write_config_dword(dev, 0x1c, 0x10000000);
+	pci_write_config_dword(dev, 0x20, 0x17fff000);
+	pci_write_config_dword(dev, 0x2c, 0);
+	pci_write_config_dword(dev, 0x30, 0xfffc);
+
+	pci_read_config_word(dev, BRGCNT, &brgcnt);
+	brgcnt &= ~IREQ_INT;
+	pci_write_config_word(dev, BRGCNT, brgcnt);
+
+	pci_read_config_dword(dev, SYSCNT, &syscnt);
+	syscnt &= ~(BAD_VCC_REQ_DISB|PCPCI_EN|CH_ASSIGN_MASK|SUB_ID_WR_EN|PCI_CLK_RIN);
+	syscnt |= (CH_ASSIGN_NODMA|ASYN_INT_MODE);
+	pci_write_config_dword(dev, SYSCNT, syscnt);
+
+	pci_read_config_byte(dev, DEVCNT, &devcnt);
+	devcnt &= ~(ZOOM_VIDEO_EN|SR_PCI_INT_SEL_MASK|PCI_INT_MODE|IRQ_MODE);
+	devcnt |= (SR_PCI_INT_SEL_NONE|IFG);
+	pci_write_config_byte(dev, DEVCNT, devcnt);
+
+	pci_write_config_byte(dev, CHIPCNT, S_PREF_DISB);
+
+	pci_write_config_byte(dev, SERRDIS, 0);
+}
+
+static int cardu_init(unsigned int slot)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[slot];
+
+	cardu_pciregs_init(socket->dev);
+
+	/* CARD_SC bits are cleared by reading CARD_SC. */
+	exca_writeb(socket, GLO_CNT, 0);
+
+	socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
+	socket->cap.irq_mask = 0;
+	socket->cap.map_size = 0x1000;
+	socket->cap.pci_irq  = socket->dev->irq;
+	socket->events = 0;
+	spin_lock_init(socket->event_lock);
+
+	/* Enable PC Card status interrupts */
+	exca_writeb(socket, CARD_SCI, CARD_DT_EN|RDY_EN|BAT_WAR_EN|BAT_DEAD_EN);
+
+	return 0;
+}
+
+static int cardu_suspend(unsigned int slot)
+{
+	return -EINVAL;
+}
+
+static int cardu_register_callback(unsigned int sock,
+                                           void (*handler)(void *, unsigned int),
+                                           void * info)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+
+	socket->handler = handler;
+	socket->info = info;
+
+	if (handler)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int cardu_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+
+	*cap = socket->cap;
+
+	return 0;
+}
+
+static int cardu_get_status(unsigned int sock, u_int *value)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint32_t state;
+	uint8_t status;
+	u_int val = 0;
+
+	status = exca_readb(socket, IF_STATUS);
+	if (status & CARD_PWR) val |= SS_POWERON;
+	if (status & READY) val |= SS_READY;
+	if (status & CARD_WP) val |= SS_WRPROT;
+	if ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2))
+		val |= SS_DETECT;
+	if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) {
+		if (status & STSCHG) val |= SS_STSCHG;
+	} else {
+		status &= BV_DETECT_MASK;
+		if (status != BV_DETECT_GOOD) {
+			if (status == BV_DETECT_WARN) val |= SS_BATWARN;
+			else val |= SS_BATDEAD;
+		}
+	}
+
+	state = cardbus_socket_readl(socket, SKT_PRE_STATE);
+	if (state & VOL_3V_CARD_DT) val |= SS_3VCARD;
+	if (state & VOL_XV_CARD_DT) val |= SS_XVCARD;
+	if (state & CB_CARD_DT) val |= SS_CARDBUS;
+	if (!(state &
+	      (VOL_YV_CARD_DT|VOL_XV_CARD_DT|VOL_3V_CARD_DT|VOL_5V_CARD_DT|CCD20|CCD10)))
+		val |= SS_PENDING;
+
+	*value = val;
+
+	return 0;
+}
+
+static inline u_char get_Vcc_value(uint8_t val)
+{
+	switch (val & VCC_MASK) {
+	case VCC_3V:
+		return 33;
+	case VCC_5V:
+		return 50;
+	}
+
+	return 0;
+}
+
+static inline u_char get_Vpp_value(uint8_t val)
+{
+	switch (val & VPP_MASK) {
+	case VPP_12V:
+		return 120;
+	case VPP_VCC:
+		return get_Vcc_value(val);
+	}
+
+	return 0;
+}
+
+static int cardu_get_socket(unsigned int sock, socket_state_t *state)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint8_t val;
+
+	val = exca_readb(socket, PWR_CNT);
+	state->Vcc = get_Vcc_value(val);
+	state->Vpp = get_Vpp_value(val);
+	state->flags = 0;
+	if (val & CARD_OUT_EN) state->flags |= SS_OUTPUT_ENA;
+
+	val = exca_readb(socket, INT_GEN_CNT);
+	if (!(val & CARD_REST0)) state->flags |= SS_RESET;
+	if (val & CARD_TYPE_IO) state->flags |= SS_IOCARD;
+
+	return 0;
+}
+
+static inline uint8_t set_Vcc_value(u_char Vcc)
+{
+	switch (Vcc) {
+	case 33:
+		return VCC_3V;
+	case 50:
+		return VCC_5V;
+	}
+
+	return VCC_0V;
+}
+
+static inline uint8_t set_Vpp_value(u_char Vpp)
+{
+	switch (Vpp) {
+	case 33:
+	case 50:
+		return VPP_VCC;
+	case 120:
+		return VPP_12V;
+	}
+
+	return VPP_0V;
+}
+
+static int cardu_set_socket(unsigned int sock, socket_state_t *state)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint8_t val;
+
+	if (((state->Vpp == 33) || (state->Vpp == 50)) && (state->Vpp != state->Vcc))
+			return -EINVAL;
+
+	val = set_Vcc_value(state->Vcc);
+	val |= set_Vpp_value(state->Vpp);
+	if (state->flags & SS_OUTPUT_ENA) val |= CARD_OUT_EN;
+	exca_writeb(socket, PWR_CNT, val);
+
+	val = exca_readb(socket, INT_GEN_CNT) & CARD_REST0;
+	if (state->flags & SS_RESET) val &= ~CARD_REST0;
+	else val |= CARD_REST0;
+	if (state->flags & SS_IOCARD) val |= CARD_TYPE_IO;
+	exca_writeb(socket, INT_GEN_CNT, val);
+
+	return 0;
+}
+
+static int cardu_get_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint8_t ioctl, window;
+	u_char map;
+
+	map = io->map;
+	if (map > 1)
+		return -EINVAL; 
+
+	io->start = exca_readw(socket, IO_WIN_SA(map));
+	io->stop = exca_readw(socket, IO_WIN_EA(map));
+
+	ioctl = exca_readb(socket, IO_WIN_CNT);
+	window = exca_readb(socket, ADR_WIN_EN);
+	io->flags  = (window & IO_WIN_EN(map)) ? MAP_ACTIVE : 0;
+	if (ioctl & IO_WIN_DATA_AUTOSZ(map))
+		io->flags |= MAP_AUTOSZ;
+	else if (ioctl & IO_WIN_DATA_16BIT(map))
+		io->flags |= MAP_16BIT;
+
+	return 0;
+}
+
+static int cardu_set_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint16_t ioctl;
+	uint8_t window, enable;
+	u_char map;
+
+	map = io->map;
+	if (map > 1)
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	enable = IO_WIN_EN(map);
+
+	if (window & enable) {
+		window &= ~enable;
+		exca_writeb(socket, ADR_WIN_EN, window);
+	}
+
+	exca_writew(socket, IO_WIN_SA(map), io->start);
+	exca_writew(socket, IO_WIN_EA(map), io->stop);
+
+	ioctl = exca_readb(socket, IO_WIN_CNT) & ~IO_WIN_CNT_MASK(map);
+	if (io->flags & MAP_AUTOSZ) ioctl |= IO_WIN_DATA_AUTOSZ(map);
+	else if (io->flags & MAP_16BIT) ioctl |= IO_WIN_DATA_16BIT(map);
+	exca_writeb(socket, IO_WIN_CNT, ioctl);
+
+	if (io->flags & MAP_ACTIVE)
+		exca_writeb(socket, ADR_WIN_EN, window | enable);
+
+	return 0;
+}
+
+static int cardu_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint32_t start, stop, offset, page;
+	uint8_t window;
+	u_char map;
+
+	map = mem->map;
+	if (map > 4)
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	mem->flags = (window & MEM_WIN_EN(map)) ? MAP_ACTIVE : 0;
+
+	start = exca_readw(socket, MEM_WIN_SA(map));
+	mem->flags |= (start & MEM_WIN_DSIZE) ? MAP_16BIT : 0;
+	start = (start & 0x0fff) << 12;
+
+	stop = exca_readw(socket, MEM_WIN_EA(map));
+	stop = ((stop & 0x0fff) << 12) + 0x0fff;
+
+	offset = exca_readw(socket, MEM_WIN_OA(map));
+	mem->flags |= (offset & MEM_WIN_WP) ? MAP_WRPROT : 0;
+	mem->flags |= (offset & MEM_WIN_REGSET) ? MAP_ATTRIB : 0;
+	offset = ((offset & 0x3fff) << 12) + start;
+	mem->card_start = offset & 0x03ffffff;
+
+	page = exca_readb(socket, MEM_WIN_SAU(map)) << 24;
+	mem->sys_start = start + page;
+	mem->sys_stop = start + page;
+
+	return 0;
+}
+
+static int cardu_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint16_t value;
+	uint8_t window, enable;
+	u_long sys_start, sys_stop, card_start;
+	u_char map;
+
+	map = mem->map;
+	sys_start = mem->sys_start;
+	sys_stop = mem->sys_stop;
+	card_start = mem->card_start;
+
+	if (map > 4 || sys_start > sys_stop || ((sys_start ^ sys_stop) >> 24) ||
+	    (card_start >> 26))
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	enable = MEM_WIN_EN(map);
+	if (window & enable) {
+		window &= ~enable;
+		exca_writeb(socket, ADR_WIN_EN, window);
+	}
+
+	exca_writeb(socket, MEM_WIN_SAU(map), sys_start >> 24);
+
+	value = (sys_start >> 12) & 0x0fff;
+	if (mem->flags & MAP_16BIT) value |= MEM_WIN_DSIZE;
+	exca_writew(socket, MEM_WIN_SA(map), value);
+
+	value = (sys_stop >> 12) & 0x0fff;
+	exca_writew(socket, MEM_WIN_EA(map), value);
+
+	value = ((card_start - sys_start) >> 12) & 0x3fff;
+	if (mem->flags & MAP_WRPROT) value |= MEM_WIN_WP;
+	if (mem->flags & MAP_ATTRIB) value |= MEM_WIN_REGSET;
+	exca_writew(socket, MEM_WIN_OA(map), value);
+
+	if (mem->flags & MAP_ACTIVE)
+		exca_writeb(socket, ADR_WIN_EN, window | enable);
+
+	return 0;
+}
+
+static void cardu_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+}
+
+static struct pccard_operations cardu_operations = {
+	.init			= cardu_init,
+	.suspend		= cardu_suspend,
+	.register_callback	= cardu_register_callback,
+	.inquire_socket		= cardu_inquire_socket,
+	.get_status		= cardu_get_status,
+	.get_socket		= cardu_get_socket,
+	.set_socket		= cardu_set_socket,
+	.get_io_map		= cardu_get_io_map,
+	.set_io_map		= cardu_set_io_map,
+	.get_mem_map		= cardu_get_mem_map,
+	.set_mem_map		= cardu_set_mem_map,
+	.proc_setup		= cardu_proc_setup,
+};
+
+static void cardu_bh(void *data)
+{
+	vrc4173_socket_t *socket = (vrc4173_socket_t *)data;
+	uint16_t events;
+
+	spin_lock_irq(&socket->event_lock);
+	events = socket->events;
+	socket->events = 0;
+	spin_unlock_irq(&socket->event_lock);
+
+	if (socket->handler)
+		socket->handler(socket->info, events);
+}
+
+static uint16_t get_events(vrc4173_socket_t *socket)
+{
+	uint16_t events = 0;
+	uint8_t csc, status;
+
+	status = exca_readb(socket, IF_STATUS);
+	csc = exca_readb(socket, CARD_SC);
+	if ((csc & CARD_DT_CHG) && 
+	    ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2)))
+		events |= SS_DETECT;
+
+	if ((csc & RDY_CHG) && (status & READY))
+		events |= SS_READY;
+
+	if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) {
+		if ((csc & BAT_DEAD_ST_CHG) && (status & STSCHG))
+			events |= SS_STSCHG;
+	} else {
+		if (csc & (BAT_WAR_CHG|BAT_DEAD_ST_CHG)) {
+			if ((status & BV_DETECT_MASK) != BV_DETECT_GOOD) {
+				if (status == BV_DETECT_WARN) events |= SS_BATWARN;
+				else events |= SS_BATDEAD;
+			}
+		}
+	}
+
+	return events;
+}
+
+static void cardu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id;
+	uint16_t events;
+
+	socket->tq_task.routine = cardu_bh;
+	socket->tq_task.data = socket;
+
+	events = get_events(socket);
+	if (events) {
+		spin_lock(&socket->event_lock);
+		socket->events |= events;
+		spin_unlock(&socket->event_lock);
+		schedule_task(&socket->tq_task);
+	}
+}
+
+static int __devinit vrc4173_cardu_probe(struct pci_dev *dev,
+                                         const struct pci_device_id *ent)
+{
+	vrc4173_socket_t *socket;
+	unsigned long start, len, flags;
+	int slot, err;
+
+	slot = vrc4173_cardu_slots++;
+	socket = &cardu_sockets[slot];
+	if (socket->noprobe != 0)
+		return -EBUSY;
+
+	sprintf(socket->name, "NEC VRC4173 CARDU%1d", slot+1);
+
+	if ((err = pci_enable_device(dev)) < 0)
+		return err;
+
+	start = pci_resource_start(dev, 0);
+	if (start == 0)
+		return -ENODEV;
+
+	len = pci_resource_len(dev, 0);
+	if (len == 0)
+		return -ENODEV;
+
+	if (((flags = pci_resource_flags(dev, 0)) & IORESOURCE_MEM) == 0)
+		return -EBUSY;
+
+	if ((err = pci_request_regions(dev, socket->name)) < 0)
+		return err;
+
+	socket->base = ioremap(start, len);
+	if (socket->base == NULL)
+		return -ENODEV;
+
+	socket->dev = dev;
+
+	socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1);
+	if (socket->pcmcia_socket == NULL) {
+		iounmap(socket->base);
+		socket->base = NULL;
+		return -ENOMEM;
+	}
+
+	if (request_irq(dev->irq, cardu_interrupt, SA_SHIRQ, socket->name, socket) < 0) {
+		pcmcia_unregister_socket(socket->pcmcia_socket);
+		socket->pcmcia_socket = NULL;
+		iounmap(socket->base);
+		socket->base = NULL;
+		return -EBUSY;
+	}
+
+	printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq);
+
+	return 0;
+}
+
+static int __devinit vrc4173_cardu_setup(char *options)
+{
+	if (options == NULL || *options == '\0')
+		return 0;
+
+	if (strncmp(options, "cardu1:", 7) == 0) {
+		options += 7;
+		if (*options != '\0') {
+			if (strncmp(options, "noprobe", 7) == 0) {
+				cardu_sockets[CARDU1].noprobe = 1;
+				options += 7;
+			}
+
+			if (*options != ',')
+				return 0;
+		} else
+			return 0;
+	}
+
+	if (strncmp(options, "cardu2:", 7) == 0) {
+		options += 7;
+		if ((*options != '\0') && (strncmp(options, "noprobe", 7) == 0))
+			cardu_sockets[CARDU2].noprobe = 1;
+	}
+
+	return 0;
+}
+
+__setup("vrc4173_cardu=", vrc4173_cardu_setup);
+
+static struct pci_device_id vrc4173_cardu_id_table[] __devinitdata = {
+	{	.vendor		= PCI_VENDOR_ID_NEC,
+		.device		= PCI_DEVICE_ID_NEC_NAPCCARD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID, },
+        {0, }
+};
+
+static struct pci_driver vrc4173_cardu_driver = {
+	.name		= "NEC VRC4173 CARDU",
+	.probe		= vrc4173_cardu_probe,
+	.id_table	= vrc4173_cardu_id_table,
+};
+
+static int __devinit vrc4173_cardu_init(void)
+{
+	vrc4173_cardu_slots = 0;
+
+	return pci_module_init(&vrc4173_cardu_driver);
+}
+
+static void __devexit vrc4173_cardu_exit(void)
+{
+	pci_unregister_driver(&vrc4173_cardu_driver);
+}
+
+module_init(vrc4173_cardu_init);
+module_exit(vrc4173_cardu_exit);
diff -urN linux-2.4.23-bk1/drivers/pcmcia/vrc4173_cardu.h linux-2.4.23-bk2/drivers/pcmcia/vrc4173_cardu.h
--- linux-2.4.23-bk1/drivers/pcmcia/vrc4173_cardu.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/drivers/pcmcia/vrc4173_cardu.h	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,247 @@
+/*
+ * FILE NAME
+ *	drivers/pcmcia/vrc4173_cardu.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Include file for NEC VRC4173 CARDU.
+ *
+ * Copyright 2002 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ *  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 SOFTWARE IS PROVIDED ``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.
+ *
+ *  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.
+ */
+#ifndef _VRC4173_CARDU_H
+#define _VRC4173_CARDU_H
+
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+
+#define CARDU_MAX_SOCKETS	2
+#define CARDU1			0
+#define CARDU2			1
+
+/*
+ * PCI Configuration Registers
+ */
+#define BRGCNT			0x3e
+ #define POST_WR_EN		0x0400
+ #define MEM1_PREF_EN		0x0200
+ #define MEM0_PREF_EN		0x0100
+ #define IREQ_INT		0x0080
+ #define CARD_RST		0x0040
+ #define MABORT_MODE		0x0020
+ #define VGA_EN			0x0008
+ #define ISA_EN			0x0004
+ #define SERR_EN		0x0002
+ #define PERR_EN		0x0001
+
+#define SYSCNT			0x80
+ #define BAD_VCC_REQ_DISB	0x00200000
+ #define PCPCI_EN		0x00080000
+ #define CH_ASSIGN_MASK		0x00070000
+ #define CH_ASSIGN_NODMA	0x00040000
+ #define SUB_ID_WR_EN		0x00000008
+ #define ASYN_INT_MODE		0x00000004
+ #define PCI_CLK_RIN		0x00000002
+
+#define DEVCNT			0x91
+ #define ZOOM_VIDEO_EN		0x40
+ #define SR_PCI_INT_SEL_MASK	0x18
+ #define SR_PCI_INT_SEL_NONE	0x00
+ #define PCI_INT_MODE		0x04
+ #define IRQ_MODE		0x02
+ #define IFG			0x01
+
+#define CHIPCNT			0x9c
+ #define S_PREF_DISB		0x10
+
+#define SERRDIS			0x9f
+ #define SERR_DIS_MAB		0x10
+ #define SERR_DIS_TAB		0x08
+ #define SERR_DIS_DT_PERR	0x04
+
+/*
+ * ExCA Registers
+ */
+#define EXCA_REGS_BASE		0x800
+#define EXCA_REGS_SIZE		0x800
+
+#define ID_REV			0x000
+ #define IF_TYPE_16BIT		0x80
+
+#define IF_STATUS		0x001
+ #define CARD_PWR		0x40
+ #define READY			0x20
+ #define CARD_WP		0x10
+ #define CARD_DETECT2		0x08
+ #define CARD_DETECT1		0x04
+ #define BV_DETECT_MASK		0x03
+ #define BV_DETECT_GOOD		0x03	/* Memory card */
+ #define BV_DETECT_WARN		0x02
+ #define BV_DETECT_BAD1		0x01
+ #define BV_DETECT_BAD0		0x00
+ #define STSCHG			0x02	/* I/O card */
+ #define SPKR			0x01
+
+#define PWR_CNT			0x002
+ #define CARD_OUT_EN		0x80
+ #define VCC_MASK		0x18
+ #define VCC_3V			0x18
+ #define VCC_5V			0x10
+ #define VCC_0V			0x00
+ #define VPP_MASK		0x03
+ #define VPP_12V		0x02
+ #define VPP_VCC		0x01
+ #define VPP_0V			0x00
+
+#define INT_GEN_CNT		0x003
+ #define CARD_REST0		0x40
+ #define CARD_TYPE_MASK		0x20
+ #define CARD_TYPE_IO		0x20
+ #define CARD_TYPE_MEM		0x00
+
+#define CARD_SC			0x004
+ #define CARD_DT_CHG		0x08
+ #define RDY_CHG		0x04
+ #define BAT_WAR_CHG		0x02
+ #define BAT_DEAD_ST_CHG	0x01
+
+#define CARD_SCI		0x005
+ #define CARD_DT_EN		0x08
+ #define RDY_EN			0x04
+ #define BAT_WAR_EN		0x02
+ #define BAT_DEAD_EN		0x01
+
+#define ADR_WIN_EN		0x006
+ #define IO_WIN_EN(x)		(0x40 << (x))
+ #define MEM_WIN_EN(x)		(0x01 << (x))
+
+#define IO_WIN_CNT		0x007
+ #define IO_WIN_CNT_MASK(x)	(0x03 << ((x) << 2))
+ #define IO_WIN_DATA_AUTOSZ(x)	(0x02 << ((x) << 2))	
+ #define IO_WIN_DATA_16BIT(x)	(0x01 << ((x) << 2))	
+
+#define IO_WIN_SA(x)		(0x008 + ((x) << 2))
+#define IO_WIN_EA(x)		(0x00a + ((x) << 2))
+
+#define MEM_WIN_SA(x)		(0x010 + ((x) << 3))
+ #define MEM_WIN_DSIZE		0x8000
+
+#define MEM_WIN_EA(x)		(0x012 + ((x) << 3))
+
+#define MEM_WIN_OA(x)		(0x014 + ((x) << 3))
+ #define MEM_WIN_WP		0x8000
+ #define MEM_WIN_REGSET		0x4000
+
+#define GEN_CNT			0x016
+ #define VS2_STATUS		0x80
+ #define VS1_STATUS		0x40
+ #define EXCA_REG_RST_EN	0x02
+
+#define GLO_CNT			0x01e
+ #define FUN_INT_LEV		0x08
+ #define INT_WB_CLR		0x04
+ #define CSC_INT_LEV		0x02
+
+#define IO_WIN_OAL(x)		(0x036 + ((x) << 1))
+#define IO_WIN_OAH(x)		(0x037 + ((x) << 1))
+
+#define MEM_WIN_SAU(x)		(0x040 + (x))
+
+#define IO_SETUP_TIM		0x080
+#define IO_CMD_TIM		0x081
+#define IO_HOLD_TIM		0x082
+#define MEM_SETUP_TIM(x)	(0x084 + ((x) << 2))
+#define MEM_CMD_TIM(x)		(0x085 + ((x) << 2))
+#define MEM_HOLD_TIM(x)		(0x086 + ((x) << 2))
+ #define TIM_CLOCKS(x)		((x) - 1)
+
+#define MEM_TIM_SEL1		0x08c
+#define MEM_TIM_SEL2		0x08d
+ #define MEM_WIN_TIMSEL1(x)	(0x03 << (((x) & 3) << 1))
+
+#define MEM_WIN_PWEN		0x091
+ #define POSTWEN		0x01
+
+/*
+ * CardBus Socket Registers
+ */
+#define CARDBUS_SOCKET_REGS_BASE	0x000
+#define CARDBUS_SOCKET_REGS_SIZE	0x800
+
+#define SKT_EV			0x000
+ #define POW_CYC_EV		0x00000008
+ #define CCD2_EV		0x00000004
+ #define CCD1_EV		0x00000002
+ #define CSTSCHG_EV		0x00000001
+
+#define SKT_MASK		0x004
+ #define POW_CYC_MASK		0x00000008
+ #define CCD_MASK		0x00000006
+ #define CSC_MASK		0x00000001
+
+#define SKT_PRE_STATE		0x008
+#define SKT_FORCE_EV		0x00c
+ #define VOL_3V_SKT		0x20000000
+ #define VOL_5V_SKT		0x10000000
+ #define CVS_TEST		0x00004000
+ #define VOL_YV_CARD_DT		0x00002000
+ #define VOL_XV_CARD_DT		0x00001000
+ #define VOL_3V_CARD_DT		0x00000800
+ #define VOL_5V_CARD_DT		0x00000400
+ #define BAD_VCC_REQ		0x00000200
+ #define DATA_LOST		0x00000100
+ #define NOT_A_CARD		0x00000080
+ #define CREADY			0x00000040
+ #define CB_CARD_DT		0x00000020
+ #define R2_CARD_DT		0x00000010
+ #define POW_UP			0x00000008
+ #define CCD20			0x00000004
+ #define CCD10			0x00000002
+ #define CSTSCHG		0x00000001
+
+#define SKT_CNT			0x010
+ #define STP_CLK_EN		0x00000080
+ #define VCC_CNT_MASK		0x00000070
+ #define VCC_CNT_3V		0x00000030
+ #define VCC_CNT_5V		0x00000020
+ #define VCC_CNT_0V		0x00000000
+ #define VPP_CNT_MASK		0x00000007
+ #define VPP_CNT_3V		0x00000003
+ #define VPP_CNT_5V		0x00000002
+ #define VPP_CNT_12V		0x00000001
+ #define VPP_CNT_0V		0x00000000
+
+typedef struct vrc4173_socket {
+	int noprobe;
+	struct pci_dev *dev;
+	void *base;
+	void (*handler)(void *, unsigned int);
+	void *info;
+	socket_cap_t cap;
+	spinlock_t event_lock;
+	uint16_t events;
+	struct socket_info_t *pcmcia_socket;
+	struct tq_struct tq_task;
+	char name[20];
+} vrc4173_socket_t;
+
+#endif /* _VRC4173_CARDU_H */
diff -urN linux-2.4.23-bk1/drivers/scsi/3w-xxxx.c linux-2.4.23-bk2/drivers/scsi/3w-xxxx.c
--- linux-2.4.23-bk1/drivers/scsi/3w-xxxx.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.23-bk2/drivers/scsi/3w-xxxx.c	2003-12-03 02:49:52.000000000 -0800
@@ -173,6 +173,8 @@
    1.02.00.035 - Improve tw_allocate_memory() memory allocation.
                  Fix tw_chrdev_ioctl() to sleep correctly.
    1.02.00.036 - Increase character ioctl timeout to 60 seconds.
+   1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds
+                 for 'smartmontools' support.
 */
 
 #include <linux/module.h>
@@ -240,7 +242,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.036";
+char *tw_driver_version="1.02.00.037";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 static int twe_major = -1;
@@ -1930,12 +1932,15 @@
 			}
 
 			passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id];
-			passthru->sg_list[0].length = passthru->sector_count*512;
-			if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
-				return 1;
+			/* Don't load sg_list for non-data ATA cmds */
+			if ((passthru->param != 0) && (passthru->param != 0x8)) {
+				passthru->sg_list[0].length = passthru->sector_count*512;
+				if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
+					printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
+					return 1;
+				}
+				passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			}
-			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			tw_post_command_packet(tw_dev, request_id);
 			return 0;
 		case TW_CMD_PACKET:
@@ -2186,7 +2191,14 @@
 	switch (ioctl->opcode) {
 		case TW_ATA_PASSTHRU:
 			passthru = (TW_Passthru *)ioctl->data;
-			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
+			/* Don't return data for non-data ATA cmds */
+			if ((passthru->param != 0) && (passthru->param != 0x8))
+				memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
+			else {
+				/* For non-data cmds, return cmd pkt */
+				if (tw_dev->srb[request_id]->request_bufflen >= sizeof(TW_Command))
+					memcpy(buff, tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
+			}
 			break;
 		case TW_CMD_PACKET_WITH_DATA:
 			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
diff -urN linux-2.4.23-bk1/fs/lockd/clntlock.c linux-2.4.23-bk2/fs/lockd/clntlock.c
--- linux-2.4.23-bk1/fs/lockd/clntlock.c	2001-10-01 13:45:47.000000000 -0700
+++ linux-2.4.23-bk2/fs/lockd/clntlock.c	2003-12-03 02:49:52.000000000 -0800
@@ -188,7 +188,8 @@
 		nlmclnt_prepare_reclaim(host, newstate);
 		nlm_get_host(host);
 		MOD_INC_USE_COUNT;
-		kernel_thread(reclaimer, host, CLONE_SIGNAL);
+		if (kernel_thread(reclaimer, host, CLONE_SIGNAL) < 0)
+			MOD_DEC_USE_COUNT;
 	}
 }
 
diff -urN linux-2.4.23-bk1/fs/nfsd/nfsxdr.c linux-2.4.23-bk2/fs/nfsd/nfsxdr.c
--- linux-2.4.23-bk1/fs/nfsd/nfsxdr.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.23-bk2/fs/nfsd/nfsxdr.c	2003-12-03 02:49:52.000000000 -0800
@@ -127,6 +127,17 @@
 	if (tmp != (u32)-1 && tmp1 != (u32)-1) {
 		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 		iap->ia_mtime = tmp;
+		/*
+		 * Passing the invalid value useconds=1000000 for mtime
+		 * is a Sun convention for "set both mtime and atime to
+		 * current server time".  It's needed to make permissions
+		 * checks for the "touch" program across v2 mounts to
+		 * Solaris and Irix boxes work correctly. See description of
+		 * sattr in section 6.1 of "NFS Illustrated" by
+		 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
+		 */
+		if (tmp1 == 1000000)
+			iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
 	}
 	return p;
 }
diff -urN linux-2.4.23-bk1/fs/stat.c linux-2.4.23-bk2/fs/stat.c
--- linux-2.4.23-bk1/fs/stat.c	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.23-bk2/fs/stat.c	2003-12-03 02:49:52.000000000 -0800
@@ -26,7 +26,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -129,7 +129,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -165,7 +165,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -203,7 +203,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
diff -urN linux-2.4.23-bk1/include/linux/elf.h linux-2.4.23-bk2/include/linux/elf.h
--- linux-2.4.23-bk1/include/linux/elf.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/elf.h	2003-12-03 02:49:52.000000000 -0800
@@ -32,11 +32,16 @@
 #define PT_LOPROC  0x70000000
 #define PT_HIPROC  0x7fffffff
 #define PT_MIPS_REGINFO		0x70000000
+#define PT_MIPS_OPTIONS		0x70000001
 
 /* Flags in the e_flags field of the header */
 #define EF_MIPS_NOREORDER 0x00000001
 #define EF_MIPS_PIC       0x00000002
 #define EF_MIPS_CPIC      0x00000004
+#define EF_MIPS_ABI2      0x00000020
+#define EF_MIPS_OPTIONS_FIRST 0x00000080
+#define EF_MIPS_32BITMODE 0x00000100
+#define EF_MIPS_ABI       0x0000f000
 #define EF_MIPS_ARCH      0xf0000000
 
 /* These constants define the different elf file types */
@@ -60,7 +65,7 @@
 
 #define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */
 
-#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */
+#define EM_MIPS_RS3_LE 10	/* MIPS R3000 little-endian */
 
 #define EM_PARISC      15	/* HPPA */
 
diff -urN linux-2.4.23-bk1/include/linux/fb.h linux-2.4.23-bk2/include/linux/fb.h
--- linux-2.4.23-bk1/include/linux/fb.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.23-bk2/include/linux/fb.h	2003-12-03 02:49:52.000000000 -0800
@@ -97,6 +97,7 @@
 #define FB_ACCEL_ATI_RADEON	38	/* ATI Radeon family		*/
 #define FB_ACCEL_SIS_GLAMOUR_2  40	/* SiS 315, 650, 740		*/
 #define FB_ACCEL_SIS_XABRE	41	/* SiS 330 ("Xabre")		*/
+#define FB_ACCEL_EPSON_SED1356	42	/* Epson SED1356		*/
 
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
diff -urN linux-2.4.23-bk1/include/linux/if_vlan.h linux-2.4.23-bk2/include/linux/if_vlan.h
--- linux-2.4.23-bk1/include/linux/if_vlan.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/include/linux/if_vlan.h	2003-12-03 02:49:52.000000000 -0800
@@ -213,7 +213,9 @@
 	GET_VLAN_INGRESS_PRIORITY_CMD,
 	GET_VLAN_EGRESS_PRIORITY_CMD,
 	SET_VLAN_NAME_TYPE_CMD,
-	SET_VLAN_FLAG_CMD
+	SET_VLAN_FLAG_CMD,
+        GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+        GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
 };
 
 enum vlan_name_types {
diff -urN linux-2.4.23-bk1/include/linux/mc146818rtc.h linux-2.4.23-bk2/include/linux/mc146818rtc.h
--- linux-2.4.23-bk1/include/linux/mc146818rtc.h	2001-11-22 11:46:58.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/mc146818rtc.h	2003-12-03 02:49:52.000000000 -0800
@@ -98,4 +98,12 @@
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
 
+#ifndef RTC_IO_EXTENT
+#define RTC_IO_EXTENT	0x10	/* Only really two ports, but...	*/
+#endif
+
+#ifndef RTC_IOMAPPED
+#define RTC_IOMAPPED	1	/* Default to I/O mapping. */
+#endif
+
 #endif /* _MC146818RTC_H */
diff -urN linux-2.4.23-bk1/include/linux/netdevice.h linux-2.4.23-bk2/include/linux/netdevice.h
--- linux-2.4.23-bk1/include/linux/netdevice.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/netdevice.h	2003-12-03 02:49:52.000000000 -0800
@@ -454,6 +454,8 @@
 #endif /* CONFIG_NET_DIVERT */
 };
 
+/* 2.6 compatibility */
+#define SET_NETDEV_DEV(net, pdev) do { } while (0)
 
 struct packet_type 
 {
diff -urN linux-2.4.23-bk1/include/linux/spinlock.h linux-2.4.23-bk2/include/linux/spinlock.h
--- linux-2.4.23-bk1/include/linux/spinlock.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/spinlock.h	2003-12-03 02:49:52.000000000 -0800
@@ -3,6 +3,8 @@
 
 #include <linux/config.h>
 
+#include <asm/system.h>
+
 /*
  * These are the generic versions of the spinlocks and read-write
  * locks..
diff -urN linux-2.4.23-bk1/include/linux/sysctl.h linux-2.4.23-bk2/include/linux/sysctl.h
--- linux-2.4.23-bk1/include/linux/sysctl.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/sysctl.h	2003-12-03 02:49:52.000000000 -0800
@@ -220,7 +220,8 @@
 	NET_CORE_NO_CONG=14,
 	NET_CORE_LO_CONG=15,
 	NET_CORE_MOD_CONG=16,
-	NET_CORE_DEV_WEIGHT=17
+	NET_CORE_DEV_WEIGHT=17,
+	NET_CORE_SOMAXCONN=18,
 };
 
 /* /proc/sys/net/ethernet */
diff -urN linux-2.4.23-bk1/include/linux/videodev.h linux-2.4.23-bk2/include/linux/videodev.h
--- linux-2.4.23-bk1/include/linux/videodev.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/include/linux/videodev.h	2003-12-03 02:49:52.000000000 -0800
@@ -421,6 +421,8 @@
 #define VID_HARDWARE_VICAM      34
 #define VID_HARDWARE_SF16FMR2	35
 #define VID_HARDWARE_W9968CF	36
+#define VID_HARDWARE_SAA7114H	36
+
 #endif /* __LINUX_VIDEODEV_H */
 
 /*
diff -urN linux-2.4.23-bk1/include/net/sctp/sctp.h linux-2.4.23-bk2/include/net/sctp/sctp.h
--- linux-2.4.23-bk1/include/net/sctp/sctp.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/include/net/sctp/sctp.h	2003-12-03 02:49:52.000000000 -0800
@@ -89,7 +89,6 @@
 #include <net/snmp.h>
 #include <net/sctp/structs.h>
 #include <net/sctp/constants.h>
-#include <net/sctp/sm.h>
 
 
 /* Set SCTP_DEBUG flag via config if not already set. */
diff -urN linux-2.4.23-bk1/include/net/sock.h linux-2.4.23-bk2/include/net/sock.h
--- linux-2.4.23-bk1/include/net/sock.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/include/net/sock.h	2003-12-03 02:49:52.000000000 -0800
@@ -1184,6 +1184,7 @@
 static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	int err = 0;
+	int skb_len;
 
 	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
 	   number of warnings when compiling with -W --ANK
@@ -1203,9 +1204,17 @@
 
 	skb->dev = NULL;
 	skb_set_owner_r(skb, sk);
+
+	/* Cache the SKB length before we tack it onto the receive
+	 * queue.  Once it is added it no longer belongs to us and
+	 * may be freed by other threads of control pulling packets
+	 * from the queue.
+	 */
+	skb_len = skb->len;
+
 	skb_queue_tail(&sk->receive_queue, skb);
 	if (!sk->dead)
-		sk->data_ready(sk,skb->len);
+		sk->data_ready(sk,skb_len);
 out:
 	return err;
 }
diff -urN linux-2.4.23-bk1/include/pcmcia/cs_types.h linux-2.4.23-bk2/include/pcmcia/cs_types.h
--- linux-2.4.23-bk1/include/pcmcia/cs_types.h	2001-10-11 09:43:29.000000000 -0700
+++ linux-2.4.23-bk2/include/pcmcia/cs_types.h	2003-12-03 02:49:52.000000000 -0800
@@ -36,7 +36,7 @@
 #include <sys/types.h>
 #endif
 
-#ifdef __arm__
+#if defined(__arm__) || defined(__mips__)
 typedef u_int   ioaddr_t;
 #else
 typedef u_short	ioaddr_t;
diff -urN linux-2.4.23-bk1/include/video/e1356fb.h linux-2.4.23-bk2/include/video/e1356fb.h
--- linux-2.4.23-bk1/include/video/e1356fb.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk2/include/video/e1356fb.h	2003-12-03 02:49:52.000000000 -0800
@@ -0,0 +1,73 @@
+/*
+ *	e1356fb.h  --  Epson SED1356 Framebuffer Driver IOCTL Interface
+ *
+ *	Copyright 2001, 2002, 2003 MontaVista Software Inc.
+ *	Author: MontaVista Software, Inc.
+ *		stevel@mvista.com or source@mvista.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  SOFTWARE  IS PROVIDED   ``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.
+ *
+ *	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.
+ */
+
+/*
+ * IOCTLs to SED1356 fb driver. 0x45 is 'E' for Epson.
+ */
+#define FBIO_SED1356_BITBLT 0x4500
+
+typedef struct {
+	int   operation;
+	int   rop;
+	int   src_y;
+	int   src_x;
+	int   src_width;
+	int   src_height;
+	int   dst_y;
+	int   dst_x;
+	int   dst_width;
+	int   dst_height;
+	int   pattern_x;
+	int   pattern_y;
+	int   attribute;
+	unsigned int bg_color;
+	unsigned int fg_color;
+	unsigned short* src;
+	int   srcsize;
+	int   srcstride;
+} blt_info_t;
+
+enum blt_attribute_t {
+	BLT_ATTR_TRANSPARENT = 1
+};
+
+enum blt_operation_t {
+	BLT_WRITE_ROP = 0,
+	BLT_READ,
+	BLT_MOVE_POS_ROP,
+	BLT_MOVE_NEG_ROP,
+	BLT_WRITE_TRANSP,
+	BLT_MOVE_POS_TRANSP,
+	BLT_PAT_FILL_ROP,
+	BLT_PAT_FILL_TRANSP,
+	BLT_COLOR_EXP,
+	BLT_COLOR_EXP_TRANSP,
+	BLT_MOVE_COLOR_EXP,
+	BLT_MOVE_COLOR_EXP_TRANSP,
+	BLT_SOLID_FILL
+};
diff -urN linux-2.4.23-bk1/kernel/fork.c linux-2.4.23-bk2/kernel/fork.c
--- linux-2.4.23-bk1/kernel/fork.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/kernel/fork.c	2003-12-03 02:49:52.000000000 -0800
@@ -669,6 +669,7 @@
 	 * than the amount of processes root is running. -- Rik
 	 */
 	if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur
+		      && p->user != &root_user
 	              && !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
 		goto bad_fork_free;
 
diff -urN linux-2.4.23-bk1/net/8021q/vlan.c linux-2.4.23-bk2/net/8021q/vlan.c
--- linux-2.4.23-bk1/net/8021q/vlan.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/8021q/vlan.c	2003-12-03 02:49:52.000000000 -0800
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
@@ -657,15 +657,9 @@
 int vlan_ioctl_handler(unsigned long arg)
 {
 	int err = 0;
+        unsigned short vid = 0;
 	struct vlan_ioctl_args args;
 
-	/* everything here needs root permissions, except aguably the
-	 * hack ioctls for sending packets.  However, I know _I_ don't
-	 * want users running that on my network! --BLG
-	 */
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	if (copy_from_user(&args, (void*)arg,
                            sizeof(struct vlan_ioctl_args)))
 		return -EFAULT;
@@ -680,24 +674,33 @@
 
 	switch (args.cmd) {
 	case SET_VLAN_INGRESS_PRIORITY_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
 		err = vlan_dev_set_ingress_priority(args.device1,
 						    args.u.skb_priority,
 						    args.vlan_qos);
 		break;
 
 	case SET_VLAN_EGRESS_PRIORITY_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		err = vlan_dev_set_egress_priority(args.device1,
 						   args.u.skb_priority,
 						   args.vlan_qos);
 		break;
 
 	case SET_VLAN_FLAG_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		err = vlan_dev_set_vlan_flag(args.device1,
 					     args.u.flag,
 					     args.vlan_qos);
 		break;
 
 	case SET_VLAN_NAME_TYPE_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		if ((args.u.name_type >= 0) &&
 		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
 			vlan_name_type = args.u.name_type;
@@ -707,17 +710,9 @@
 		}
 		break;
 
-		/* TODO:  Figure out how to pass info back...
-		   case GET_VLAN_INGRESS_PRIORITY_IOCTL:
-		   err = vlan_dev_get_ingress_priority(args);
-		   break;
-
-		   case GET_VLAN_EGRESS_PRIORITY_IOCTL:
-		   err = vlan_dev_get_egress_priority(args);
-		   break;
-		*/
-
 	case ADD_VLAN_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		/* we have been given the name of the Ethernet Device we want to
 		 * talk to:  args.dev1	 We also have the
 		 * VLAN ID:  args.u.VID
@@ -730,12 +725,53 @@
 		break;
 
 	case DEL_VLAN_CMD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		/* Here, the args.dev1 is the actual VLAN we want
 		 * to get rid of.
 		 */
 		err = unregister_vlan_device(args.device1);
 		break;
 
+	case GET_VLAN_INGRESS_PRIORITY_CMD:
+		/* TODO:  Implement
+		err = vlan_dev_get_ingress_priority(args);
+		if (copy_to_user((void*)arg, &args,
+				 sizeof(struct vlan_ioctl_args))) {
+			err = -EFAULT;
+		}
+		*/
+		err = -EINVAL;
+		break;
+
+	case GET_VLAN_EGRESS_PRIORITY_CMD:
+		/* TODO:  Implement
+		err = vlan_dev_get_egress_priority(args.device1, &(args.args);
+		if (copy_to_user((void*)arg, &args,
+				 sizeof(struct vlan_ioctl_args))) {
+			err = -EFAULT;
+		}
+		*/
+		err = -EINVAL;
+		break;
+
+	case GET_VLAN_REALDEV_NAME_CMD:
+		err = vlan_dev_get_realdev_name(args.device1, args.u.device2);
+		if (copy_to_user((void*)arg, &args,
+				 sizeof(struct vlan_ioctl_args))) {
+			err = -EFAULT;
+		}
+		break;
+
+	case GET_VLAN_VID_CMD:
+		err = vlan_dev_get_vid(args.device1, &vid);
+		args.u.VID = vid;
+		if (copy_to_user((void*)arg, &args,
+				 sizeof(struct vlan_ioctl_args))) {
+			err = -EFAULT;
+		}
+		break;
+		
 	default:
 		/* pass on to underlying device instead?? */
 		printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
diff -urN linux-2.4.23-bk1/net/8021q/vlan.h linux-2.4.23-bk2/net/8021q/vlan.h
--- linux-2.4.23-bk1/net/8021q/vlan.h	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.23-bk2/net/8021q/vlan.h	2003-12-03 02:49:52.000000000 -0800
@@ -73,5 +73,7 @@
 int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
 int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val);
 void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
+int vlan_dev_get_realdev_name(const char *dev_name, char* result);
+int vlan_dev_get_vid(const char *dev_name, unsigned short* result);
 
 #endif /* !(__BEN_VLAN_802_1Q_INC__) */
diff -urN linux-2.4.23-bk1/net/8021q/vlan_dev.c linux-2.4.23-bk2/net/8021q/vlan_dev.c
--- linux-2.4.23-bk1/net/8021q/vlan_dev.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/8021q/vlan_dev.c	2003-12-03 02:49:52.000000000 -0800
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
@@ -636,6 +636,60 @@
 	return -EINVAL;
 }
 
+
+int vlan_dev_get_realdev_name(const char *dev_name, char* result)
+{
+	struct net_device *dev = dev_get_by_name(dev_name);
+	int rv = 0;
+	
+	if (dev) {
+		if (dev->priv_flags & IFF_802_1Q_VLAN) {
+			strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23);
+			dev_put(dev);
+			rv = 0;
+		} else {
+			/*printk(KERN_ERR 
+			       "%s: %s is not a vlan device, priv_flags: %hX.\n",
+			       __FUNCTION__, dev->name, dev->priv_flags);*/
+			dev_put(dev);
+			rv = -EINVAL;
+		}
+	} else {
+		/* printk(KERN_ERR	 "%s: Could not find device: %s\n", 
+		   __FUNCTION__, dev_name); */
+		rv = -ENODEV;
+	}
+
+	return rv;
+}
+
+int vlan_dev_get_vid(const char *dev_name, unsigned short* result)
+{
+	struct net_device *dev = dev_get_by_name(dev_name);
+	int rv = 0;
+	
+	if (dev) {
+		if (dev->priv_flags & IFF_802_1Q_VLAN) {
+			*result = VLAN_DEV_INFO(dev)->vlan_id;
+			dev_put(dev);
+			rv = 0;
+		} else {
+			/*printk(KERN_ERR 
+			       "%s: %s is not a vlan device, priv_flags: %hX.\n",
+			       __FUNCTION__, dev->name, dev->priv_flags);*/
+			dev_put(dev);
+			rv = -EINVAL;
+		}
+	} else {
+		/* printk(KERN_ERR	 "%s: Could not find device: %s\n", 
+		   __FUNCTION__, dev_name);*/
+		rv = -ENODEV;
+	}
+
+	return rv;
+}
+
+
 int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p)
 {
 	struct sockaddr *addr = (struct sockaddr *)(addr_struct_p);
diff -urN linux-2.4.23-bk1/net/core/sysctl_net_core.c linux-2.4.23-bk2/net/core/sysctl_net_core.c
--- linux-2.4.23-bk1/net/core/sysctl_net_core.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/core/sysctl_net_core.c	2003-12-03 02:49:52.000000000 -0800
@@ -28,6 +28,7 @@
 
 extern int sysctl_core_destroy_delay;
 extern int sysctl_optmem_max;
+extern int sysctl_somaxconn;
 extern int sysctl_hot_list_len;
 
 #ifdef CONFIG_NET_DIVERT
@@ -88,6 +89,9 @@
 	 (void *)sysctl_divert_version, 32, 0444, NULL,
 	 &proc_dostring},
 #endif /* CONFIG_NET_DIVERT */
+	{NET_CORE_SOMAXCONN, "somaxconn",
+	 &sysctl_somaxconn, sizeof(int), 0644, NULL,
+	 &proc_dointvec },
 #endif /* CONFIG_NET */
 	{ 0 }
 };
diff -urN linux-2.4.23-bk1/net/econet/af_econet.c linux-2.4.23-bk2/net/econet/af_econet.c
--- linux-2.4.23-bk1/net/econet/af_econet.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.23-bk2/net/econet/af_econet.c	2003-12-03 02:49:52.000000000 -0800
@@ -1033,14 +1033,14 @@
 	if (! edev)
 	{
 		kfree_skb(skb);
-		return 0;
+		return NET_RX_DROP;
 	}
 
 	if (skb->len < sizeof(struct ec_framehdr))
 	{
 		/* Frame is too small to be any use */
 		kfree_skb(skb);
-		return 0;
+		return NET_RX_DROP;
 	}
 
 	/* First check for encapsulated IP */
@@ -1056,11 +1056,15 @@
 	if (!sk) 
 	{
 		kfree_skb(skb);
-		return 0;
+		return NET_RX_DROP;
 	}
 
-	return ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 
-			       hdr->port);
+	if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 
+			    hdr->port)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+	return 0;
 }
 
 static struct packet_type econet_packet_type = {
diff -urN linux-2.4.23-bk1/net/ipv4/netfilter/ip_queue.c linux-2.4.23-bk2/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.23-bk1/net/ipv4/netfilter/ip_queue.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.23-bk2/net/ipv4/netfilter/ip_queue.c	2003-12-03 02:49:52.000000000 -0800
@@ -585,12 +585,11 @@
 	0
 };
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
-	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
-	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &queue_maxlen,
+	  sizeof(queue_maxlen), 0644,  NULL, proc_dointvec },
  	{ 0 }
 };
 
diff -urN linux-2.4.23-bk1/net/ipv4/tcp.c linux-2.4.23-bk2/net/ipv4/tcp.c
--- linux-2.4.23-bk1/net/ipv4/tcp.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/ipv4/tcp.c	2003-12-03 02:49:52.000000000 -0800
@@ -1505,19 +1505,14 @@
 		struct sk_buff * skb;
 		u32 offset;
 
-		/* Are we at urgent data? Stop if we have read anything. */
-		if (copied && tp->urg_data && tp->urg_seq == *seq)
-			break;
-
-		/* We need to check signals first, to get correct SIGURG
-		 * handling. FIXME: Need to check this doesn't impact 1003.1g
-		 * and move it down to the bottom of the loop
-		 */
-		if (signal_pending(current)) {
+		/* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */
+		if (tp->urg_data && tp->urg_seq == *seq) {
 			if (copied)
 				break;
-			copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
-			break;
+			if (signal_pending(current)) {
+				copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
+				break;
+			}
 		}
 
 		/* Next get a buffer. */
@@ -1556,6 +1551,7 @@
 			    sk->state == TCP_CLOSE ||
 			    (sk->shutdown & RCV_SHUTDOWN) ||
 			    !timeo ||
+			    signal_pending(current) ||
 			    (flags & MSG_PEEK))
 				break;
 		} else {
@@ -1585,6 +1581,11 @@
 				copied = -EAGAIN;
 				break;
 			}
+
+			if (signal_pending(current)) {
+				copied = sock_intr_errno(timeo);
+				break;
+			}
 		}
 
 		cleanup_rbuf(sk, copied);
diff -urN linux-2.4.23-bk1/net/ipv6/mcast.c linux-2.4.23-bk2/net/ipv6/mcast.c
--- linux-2.4.23-bk1/net/ipv6/mcast.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/ipv6/mcast.c	2003-12-03 02:49:52.000000000 -0800
@@ -664,7 +664,7 @@
 		goto done;
 	spin_unlock_bh(&mc->mca_lock);
 
-	if (dev->flags&IFF_UP)
+	if (!mc->idev->dead)
 		igmp6_leave_group(mc);
 
 	spin_lock_bh(&mc->mca_lock);
@@ -957,8 +957,9 @@
 {
 	unsigned long delay = resptime;
 
-	/* Do not start timer for addresses with link/host scope */
-	if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
+	/* Do not start timer for these addresses */
+	if (ipv6_addr_is_ll_all_nodes(&ma->mca_addr) ||
+	    IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
 		return;
 
 	if (del_timer(&ma->mca_timer)) {
@@ -976,6 +977,7 @@
 	ma->mca_timer.expires = jiffies + delay;
 	if (!mod_timer(&ma->mca_timer, jiffies + delay))
 		atomic_inc(&ma->mca_refcnt);
+	ma->mca_flags |= MAF_TIMER_RUNNING;
 	spin_unlock(&ma->mca_lock);
 }
 
@@ -1039,7 +1041,7 @@
 		/* MLDv1 router present */
 
 		/* Translate milliseconds to jiffies */
-		max_delay = ntohs(hdr->icmp6_maxdelay)*(HZ/10);
+		max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000;
 
 		switchback = (idev->mc_qrv + 1) * max_delay;
 		idev->mc_v1_seen = jiffies + switchback;
@@ -1051,7 +1053,7 @@
 		/* clear deleted report items */
 		mld_clear_delrec(idev);
 	} else if (len >= 28) {
-		max_delay = MLDV2_MRC(ntohs(mlh2->mrc))*(HZ/10);
+		max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000;
 		if (!max_delay)
 			max_delay = 1;
 		idev->mc_maxdelay = max_delay;
diff -urN linux-2.4.23-bk1/net/ipv6/netfilter/ip6_queue.c linux-2.4.23-bk2/net/ipv6/netfilter/ip6_queue.c
--- linux-2.4.23-bk1/net/ipv6/netfilter/ip6_queue.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.23-bk2/net/ipv6/netfilter/ip6_queue.c	2003-12-03 02:49:52.000000000 -0800
@@ -589,12 +589,11 @@
 	0
 };
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
-	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
-	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &queue_maxlen,
+	  sizeof(queue_maxlen), 0644,  NULL, proc_dointvec },
  	{ 0 }
 };
 
diff -urN linux-2.4.23-bk1/net/ipv6/route.c linux-2.4.23-bk2/net/ipv6/route.c
--- linux-2.4.23-bk1/net/ipv6/route.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/ipv6/route.c	2003-12-03 02:49:52.000000000 -0800
@@ -1673,13 +1673,13 @@
 static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
 {
 	struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
-	struct rtmsg *rtm;
 	int prefix;
 
-	rtm = NLMSG_DATA(arg->cb->nlh);
-	if (rtm)
+	if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) {
+		struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh);
 		prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
-	else prefix = 0;
+	} else
+		prefix = 0;
 
 	return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
 		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
diff -urN linux-2.4.23-bk1/net/ipv6/udp.c linux-2.4.23-bk2/net/ipv6/udp.c
--- linux-2.4.23-bk1/net/ipv6/udp.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/ipv6/udp.c	2003-12-03 02:49:52.000000000 -0800
@@ -565,6 +565,7 @@
 			if(!ipv6_addr_any(&np->rcv_saddr)) {
 				if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
 					return s;
+				continue;
 			}
 			if(!inet6_mc_check(s, loc_addr, rmt_addr))
 				continue;
diff -urN linux-2.4.23-bk1/net/netlink/af_netlink.c linux-2.4.23-bk2/net/netlink/af_netlink.c
--- linux-2.4.23-bk1/net/netlink/af_netlink.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/netlink/af_netlink.c	2003-12-03 02:49:52.000000000 -0800
@@ -385,6 +385,7 @@
 	struct sockaddr_nl *nladdr=(struct sockaddr_nl *)addr;
 	
 	nladdr->nl_family = AF_NETLINK;
+	nladdr->nl_pad = 0;
 	*addr_len = sizeof(*nladdr);
 
 	if (peer) {
@@ -675,6 +676,7 @@
 	if (msg->msg_name) {
 		struct sockaddr_nl *addr = (struct sockaddr_nl*)msg->msg_name;
 		addr->nl_family = AF_NETLINK;
+		addr->nl_pad    = 0;
 		addr->nl_pid	= NETLINK_CB(skb).pid;
 		addr->nl_groups	= NETLINK_CB(skb).dst_groups;
 		msg->msg_namelen = sizeof(*addr);
diff -urN linux-2.4.23-bk1/net/sched/sch_cbq.c linux-2.4.23-bk2/net/sched/sch_cbq.c
--- linux-2.4.23-bk1/net/sched/sch_cbq.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_cbq.c	2003-12-03 02:49:52.000000000 -0800
@@ -1673,6 +1673,7 @@
 		sch_tree_lock(sch);
 		*old = cl->q;
 		cl->q = new;
+		sch->q.qlen -= (*old)->q.qlen;
 		qdisc_reset(*old);
 		sch_tree_unlock(sch);
 
diff -urN linux-2.4.23-bk1/net/sched/sch_dsmark.c linux-2.4.23-bk2/net/sched/sch_dsmark.c
--- linux-2.4.23-bk1/net/sched/sch_dsmark.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_dsmark.c	2003-12-03 02:49:52.000000000 -0800
@@ -77,6 +77,7 @@
 	*old = xchg(&p->q,new);
 	if (*old)
 		qdisc_reset(*old);
+	sch->q.qlen = 0;
 	sch_tree_unlock(sch); /* @@@ move up ? */
         return 0;
 }
diff -urN linux-2.4.23-bk1/net/sched/sch_fifo.c linux-2.4.23-bk2/net/sched/sch_fifo.c
--- linux-2.4.23-bk1/net/sched/sch_fifo.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_fifo.c	2003-12-03 02:49:52.000000000 -0800
@@ -46,7 +46,7 @@
 {
 	struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data;
 
-	if (sch->stats.backlog <= q->limit) {
+	if (sch->stats.backlog + skb->len <= q->limit) {
 		__skb_queue_tail(&sch->q, skb);
 		sch->stats.backlog += skb->len;
 		sch->stats.bytes += skb->len;
@@ -107,7 +107,7 @@
 {
 	struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data;
 
-	if (sch->q.qlen <= q->limit) {
+	if (sch->q.qlen < q->limit) {
 		__skb_queue_tail(&sch->q, skb);
 		sch->stats.bytes += skb->len;
 		sch->stats.packets++;
diff -urN linux-2.4.23-bk1/net/sched/sch_generic.c linux-2.4.23-bk2/net/sched/sch_generic.c
--- linux-2.4.23-bk1/net/sched/sch_generic.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/sched/sch_generic.c	2003-12-03 02:49:52.000000000 -0800
@@ -280,7 +280,7 @@
 	list = ((struct sk_buff_head*)qdisc->data) +
 		prio2band[skb->priority&TC_PRIO_MAX];
 
-	if (list->qlen <= qdisc->dev->tx_queue_len) {
+	if (list->qlen < qdisc->dev->tx_queue_len) {
 		__skb_queue_tail(list, skb);
 		qdisc->q.qlen++;
 		qdisc->stats.bytes += skb->len;
diff -urN linux-2.4.23-bk1/net/sched/sch_gred.c linux-2.4.23-bk2/net/sched/sch_gred.c
--- linux-2.4.23-bk1/net/sched/sch_gred.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_gred.c	2003-12-03 02:49:52.000000000 -0800
@@ -110,7 +110,7 @@
 	unsigned long	qave=0;	
 	int i=0;
 
-	if (!t->initd && skb_queue_len(&sch->q) <= sch->dev->tx_queue_len) {
+	if (!t->initd && skb_queue_len(&sch->q) < sch->dev->tx_queue_len) {
 		D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n");
 		goto do_enqueue;
 	}
@@ -175,7 +175,7 @@
 	if ((q->qave+qave) < q->qth_min) {
 		q->qcount = -1;
 enqueue:
-		if (q->backlog <= q->limit) {
+		if (q->backlog + skb->len <= q->limit) {
 			q->backlog += skb->len;
 do_enqueue:
 			__skb_queue_tail(&sch->q, skb);
diff -urN linux-2.4.23-bk1/net/sched/sch_prio.c linux-2.4.23-bk2/net/sched/sch_prio.c
--- linux-2.4.23-bk1/net/sched/sch_prio.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_prio.c	2003-12-03 02:49:52.000000000 -0800
@@ -268,6 +268,7 @@
 	sch_tree_lock(sch);
 	*old = q->queues[band];
 	q->queues[band] = new;
+	sch->q.qlen -= (*old)->q.qlen;
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
 
diff -urN linux-2.4.23-bk1/net/sched/sch_red.c linux-2.4.23-bk2/net/sched/sch_red.c
--- linux-2.4.23-bk1/net/sched/sch_red.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_red.c	2003-12-03 02:49:52.000000000 -0800
@@ -257,7 +257,7 @@
 	if (q->qave < q->qth_min) {
 		q->qcount = -1;
 enqueue:
-		if (sch->stats.backlog <= q->limit) {
+		if (sch->stats.backlog + skb->len <= q->limit) {
 			__skb_queue_tail(&sch->q, skb);
 			sch->stats.backlog += skb->len;
 			sch->stats.bytes += skb->len;
diff -urN linux-2.4.23-bk1/net/sched/sch_tbf.c linux-2.4.23-bk2/net/sched/sch_tbf.c
--- linux-2.4.23-bk1/net/sched/sch_tbf.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk2/net/sched/sch_tbf.c	2003-12-03 02:49:52.000000000 -0800
@@ -268,7 +268,7 @@
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
 
 	qdisc_reset(q->qdisc);
-	skb_queue_purge(&sch->q);
+	sch->q.qlen = 0;
 	sch->stats.backlog = 0;
 	PSCHED_GET_TIME(q->t_c);
 	q->tokens = q->buffer;
@@ -463,6 +463,8 @@
 	sch_tree_lock(sch);	
 	*old = xchg(&q->qdisc, new);
 	qdisc_reset(*old);
+	sch->q.qlen = 0;
+	sch->stats.backlog = 0;
 	sch_tree_unlock(sch);
 	
 	return 0;
diff -urN linux-2.4.23-bk1/net/sctp/associola.c linux-2.4.23-bk2/net/sctp/associola.c
--- linux-2.4.23-bk1/net/sctp/associola.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/sctp/associola.c	2003-12-03 02:49:52.000000000 -0800
@@ -56,6 +56,7 @@
 #include <linux/in.h>
 #include <net/ipv6.h>
 #include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
 
 /* Forward declarations for internal functions. */
 static void sctp_assoc_bh_rcv(struct sctp_association *asoc);
diff -urN linux-2.4.23-bk1/net/sctp/outqueue.c linux-2.4.23-bk2/net/sctp/outqueue.c
--- linux-2.4.23-bk1/net/sctp/outqueue.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/sctp/outqueue.c	2003-12-03 02:49:52.000000000 -0800
@@ -53,6 +53,7 @@
 #include <net/sock.h>	  /* For skb_set_owner_w */
 
 #include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
 
 /* Declare internal functions here.  */
 static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn);
diff -urN linux-2.4.23-bk1/net/sctp/socket.c linux-2.4.23-bk2/net/sctp/socket.c
--- linux-2.4.23-bk1/net/sctp/socket.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/sctp/socket.c	2003-12-03 02:49:52.000000000 -0800
@@ -72,6 +72,7 @@
 #include <linux/socket.h> /* for sa_family_t */
 #include <net/sock.h>
 #include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
 
 /* WARNING:  Please do not remove the SCTP_STATIC attribute to
  * any of the functions below as they are used to export functions
diff -urN linux-2.4.23-bk1/net/sctp/transport.c linux-2.4.23-bk2/net/sctp/transport.c
--- linux-2.4.23-bk1/net/sctp/transport.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/sctp/transport.c	2003-12-03 02:49:52.000000000 -0800
@@ -50,6 +50,7 @@
 
 #include <linux/types.h>
 #include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
 
 /* 1st Level Abstractions.  */
 
diff -urN linux-2.4.23-bk1/net/socket.c linux-2.4.23-bk2/net/socket.c
--- linux-2.4.23-bk1/net/socket.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk2/net/socket.c	2003-12-03 02:49:53.000000000 -0800
@@ -42,7 +42,7 @@
  *		Andi Kleen	:	Some small cleanups, optimizations,
  *					and fixed a copy_from_user() bug.
  *		Tigran Aivazian	:	sys_send(args) calls sys_sendto(args, NULL, 0)
- *		Tigran Aivazian	:	Made listen(2) backlog sanity checks 
+o *		Tigran Aivazian	:	Made listen(2) backlog sanity checks 
  *					protocol-independent
  *
  *
@@ -1016,14 +1016,16 @@
  *	ready for listening.
  */
 
+int sysctl_somaxconn = SOMAXCONN;
+
 asmlinkage long sys_listen(int fd, int backlog)
 {
 	struct socket *sock;
 	int err;
 	
 	if ((sock = sockfd_lookup(fd, &err)) != NULL) {
-		if ((unsigned) backlog > SOMAXCONN)
-			backlog = SOMAXCONN;
+		if ((unsigned) backlog > sysctl_somaxconn)
+			backlog = sysctl_somaxconn;
 		err=sock->ops->listen(sock, backlog);
 		sockfd_put(sock);
 	}
