## Automatically generated incremental diff
## From:   linux-2.4.29-pre3
## To:     linux-2.4.29-rc1
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.4.29-pre3/Documentation/computone.txt linux-2.4.29-rc1/Documentation/computone.txt
--- linux-2.4.29-pre3/Documentation/computone.txt	2001-11-02 17:26:17.000000000 -0800
+++ linux-2.4.29-rc1/Documentation/computone.txt	2005-01-12 10:54:49.644637771 -0800
@@ -6,11 +6,11 @@
 These notes are for the drivers which have already been integrated into the
 kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
 
-Version: 1.2.14
-Date: 11/01/2001
+Version: 1.2.18
+Date: 12/22/2004
 Historical Author: Andrew Manison <amanison@america.net>
 Primary Author: Doug McNash
-Support: support@computone.com
+Support: mhw@wittsend.com
 Fixes and Updates: Mike Warfield <mhw@wittsend.com>
 
 This file assumes that you are using the Computone drivers which are
@@ -26,7 +26,7 @@
 products previous to the Intelliport II.
 
 This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.4.14; it will probably not work with earlier v1.X kernels,.
+to v2.4.28; it will probably not work with earlier v1.X kernels,.
 
 
 2. QUICK INSTALLATION
diff -urN linux-2.4.29-pre3/Documentation/networking/e1000.txt linux-2.4.29-rc1/Documentation/networking/e1000.txt
--- linux-2.4.29-pre3/Documentation/networking/e1000.txt	2005-01-12 10:54:46.365496856 -0800
+++ linux-2.4.29-rc1/Documentation/networking/e1000.txt	2005-01-12 10:54:49.649637986 -0800
@@ -1,14 +1,14 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-September 13, 2004
+November 17, 2004
 
 
 Contents
 ========
 
 - In This Release
-- Supported Adapters
+- Identifying Your Adapter
 - Command Line Parameters
 - Speed and Duplex Configuration
 - Additional Configurations
@@ -20,8 +20,7 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 5.x.x.  This driver includes support for Itanium(TM)2 
-and EM64T systems.
+of Adapters, version 5.x.x.  
 
 For questions related to hardware requirements, refer to the documentation 
 supplied with your Intel PRO/1000 adapter. All hardware requirements listed 
@@ -145,9 +144,11 @@
 Default Value: 256
     This value is the number of receive descriptors allocated by the driver. 
     Increasing this value allows the driver to buffer more incoming packets. 
-    Each descriptor is 16 bytes.  A receive buffer is also allocated for each
-    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending 
-    on the MTU setting. The maximum MTU size is 16110.
+    Each descriptor is 16 bytes.  A receive buffer is allocated for each
+    descriptor and can either be 2048 or 4096 bytes long, depending on the MTU 
+
+    setting. An incoming packet can span one or more receive descriptors. 
+    The maximum MTU size is 16110.
 
     NOTE: MTU designates the frame size. It only needs to be set for Jumbo 
           Frames.
@@ -251,17 +252,18 @@
   also be forced.
 
 The AutoNeg parameter is used when more control is required over the auto-
-negotiation process.  When this parameter is used, Speed and Duplex must not 
-be specified.  This parameter is a bitmap that specifies which speed and 
-duplex settings are advertised to the link partner.
-
-Bit            7      6      5       4       3      2      1       0
-Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
-Duplex                       Full            Full   Half   Full    Half
-
-For example to limit the negotiated speed/duplex on the interface to 10 Mbps 
-Half or Full duplex, set AutoNeg to 0x02: 
-    insmod e1000 AutoNeg=0x02
+negotiation process. When this parameter is used, Speed and Duplex parameters 
+must not be specified. The following table describes supported values for the 
+AutoNeg parameter:
+
+
+Speed (Mbps)             1000    100    100    10      10
+Duplex                   Full    Full   Half   Full    Half
+Value (in base 16)       0x20    0x08   0x04   0x02    0x01
+
+
+Example: insmod e1000 AutoNeg=0x03, loads e1000 and specifies (10 full duplex, 
+10 half duplex) for negotiation with the peer.
 
 Note that setting AutoNeg does not guarantee that the board will link at the 
 highest specified speed or duplex mode, but the board will link at the 
@@ -333,11 +335,7 @@
   version 1.6 or later is required for this functionality.
 
   The latest release of ethtool can be found from
-  http://sf.net/projects/gkernel.  After ethtool is installed,
-  ethtool-copy.h must be copied and renamed to ethtool.h in your kernel
-  source tree at <linux_kernel_src>/include/linux.  Backup the original
-  ethtool.h as needed before copying.  The driver then must be recompiled
-  in order to take advantage of the latest ethtool features.
+  http://sf.net/projects/gkernel.  
 
   NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support 
   for a more complete ethtool feature set can be enabled by upgrading 
diff -urN linux-2.4.29-pre3/Makefile linux-2.4.29-rc1/Makefile
--- linux-2.4.29-pre3/Makefile	2005-01-12 10:54:46.369497028 -0800
+++ linux-2.4.29-rc1/Makefile	2005-01-12 10:54:49.653638158 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 29
-EXTRAVERSION = -pre3
+EXTRAVERSION = -rc1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.29-pre3/arch/mips/kernel/irixelf.c linux-2.4.29-rc1/arch/mips/kernel/irixelf.c
--- linux-2.4.29-pre3/arch/mips/kernel/irixelf.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.29-rc1/arch/mips/kernel/irixelf.c	2005-01-12 10:54:49.837646066 -0800
@@ -130,7 +130,7 @@
 	end = PAGE_ALIGN(end);
 	if (end <= start)
 		return;
-	do_brk(start, end - start);
+	do_brk_locked(start, end - start);
 }
 
 
@@ -379,7 +379,7 @@
 
 	/* Map the last of the bss segment */
 	if (last_bss > len) {
-		do_brk(len, (last_bss - len));
+		do_brk_locked(len, (last_bss - len));
 	}
 	kfree(elf_phdata);
 
@@ -567,7 +567,7 @@
 	unsigned long v;
 	struct prda *pp;
 
-	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
+	v =  do_brk_locked (PRDA_ADDRESS, PAGE_SIZE);
 
 	if (v < 0)
 		return;
@@ -859,7 +859,7 @@
 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
 	if (bss > len)
-	  do_brk(len, bss-len);
+	  do_brk_locked(len, bss-len);
 	kfree(elf_phdata);
 	return 0;
 }
diff -urN linux-2.4.29-pre3/arch/mips64/kernel/ioctl32.c linux-2.4.29-rc1/arch/mips64/kernel/ioctl32.c
--- linux-2.4.29-pre3/arch/mips64/kernel/ioctl32.c	2005-01-12 10:54:46.598506869 -0800
+++ linux-2.4.29-rc1/arch/mips64/kernel/ioctl32.c	2005-01-12 10:54:49.974651953 -0800
@@ -2352,6 +2352,10 @@
 	IOCTL32_HANDLER(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout),
 	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE),
 	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE_MULTI),
+	IOCTL32_DEFAULT(AUTOFS_IOC_PROTSUBVER),
+	IOCTL32_DEFAULT(AUTOFS_IOC_ASKREGHOST),
+	IOCTL32_DEFAULT(AUTOFS_IOC_TOGGLEREGHOST),
+	IOCTL32_DEFAULT(AUTOFS_IOC_ASKUMOUNT),
 
 	/* DEVFS */
 	IOCTL32_DEFAULT(DEVFSDIOC_GET_PROTO_REV),
diff -urN linux-2.4.29-pre3/arch/parisc/kernel/ioctl32.c linux-2.4.29-rc1/arch/parisc/kernel/ioctl32.c
--- linux-2.4.29-pre3/arch/parisc/kernel/ioctl32.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.29-rc1/arch/parisc/kernel/ioctl32.c	2005-01-12 10:54:50.000653070 -0800
@@ -3375,6 +3375,12 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
+
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
diff -urN linux-2.4.29-pre3/arch/ppc64/kernel/ioctl32.c linux-2.4.29-rc1/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.29-pre3/arch/ppc64/kernel/ioctl32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc1/arch/ppc64/kernel/ioctl32.c	2005-01-12 10:54:50.010653500 -0800
@@ -4278,6 +4278,11 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC),
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER),
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE),
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI),
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER),
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST),
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST),
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT),
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV),
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK),
diff -urN linux-2.4.29-pre3/arch/ppc64/kernel/signal.c linux-2.4.29-rc1/arch/ppc64/kernel/signal.c
--- linux-2.4.29-pre3/arch/ppc64/kernel/signal.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc1/arch/ppc64/kernel/signal.c	2005-01-12 10:54:50.011653543 -0800
@@ -31,8 +31,8 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
+#include <asm/processor.h>
 
 #define DEBUG_SIG 0
 
@@ -138,7 +138,7 @@
 	regs->gpr[3] = EINTR;
 	regs->ccr |= 0x10000000;
 	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 		if (do_signal(&saveset, regs))
 			/*
@@ -236,22 +236,16 @@
 
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-
-	current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
-	regs->msr = current->thread.saved_msr | current->thread.fpexc_mode;
-	current->thread.saved_softe = regs->softe;
-
 	err |= __put_user(&sc->gp_regs, &sc->regs);
 	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
 	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
+	current->thread.fpscr = 0;
+
 	err |= __put_user(signr, &sc->signal);
 	err |= __put_user(handler, &sc->handler);
 	if (set != NULL)
 		err |=  __put_user(set->sig[0], &sc->oldmask);
 
-	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
-	current->thread.fpscr = 0;
-
 	return err;
 }
 
@@ -263,20 +257,33 @@
 restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
 	unsigned int err = 0;
+	int i;
+	elf_greg_t *gregs = (elf_greg_t *)regs;
+	unsigned long msr;
+
+	/* copy up to but not including MSR */
+	err |= __copy_from_user(regs, &sc->gp_regs,
+				PT_MSR * sizeof(elf_greg_t));
+	/* get the MSR value from the stack but don't put it in regs->msr */
+	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+	/* copy from orig_r3 (the word after the MSR) to the end,
+	 * but don't copy softe */
+	for (i = PT_ORIG_R3; err == 0 && i <= PT_RESULT; ++i)
+		if (i != PT_SOFTE)
+			err |= __get_user(gregs[i], &sc->gp_regs[i]);
 
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-
-	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	/* make the process reload FP regs if it executes an FP instr */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
 	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
-	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+
+	/* restore the signal mask */
 	if (set != NULL)
 		err |=  __get_user(set->sig[0], &sc->oldmask);
 
-	/* Don't allow the signal handler to change these modulo FE{0,1} */
-	regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
-	regs->softe = current->thread.saved_softe;
-
 	return err;
 }
 
diff -urN linux-2.4.29-pre3/arch/ppc64/kernel/signal32.c linux-2.4.29-rc1/arch/ppc64/kernel/signal32.c
--- linux-2.4.29-pre3/arch/ppc64/kernel/signal32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc1/arch/ppc64/kernel/signal32.c	2005-01-12 10:54:50.014653672 -0800
@@ -48,7 +48,6 @@
 #include <asm/uaccess.h>
 #include <linux/elf.h>
 #include <asm/ppc32.h>
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/ucontext.h>
 
@@ -141,23 +140,22 @@
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
+	u32 handler, restorer;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	if (sig < 0)
 		sig = -sig;
 
 	if (act) {
 		old_sigset_t32 mask;
 
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret = get_user(handler, &act->sa_handler);
+		ret |= __get_user(restorer, &act->sa_restorer);
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		ret |= __get_user(mask, &act->sa_mask);
 		if (ret)
 			return ret;
-		PPCDBG(PPCDBG_SIGNAL, "sys32_sigaction flags =%lx  \n", new_ka.sa.sa_flags);
-
+		new_ka.sa.sa_handler = (__sighandler_t)(long) handler;
+		new_ka.sa.sa_restorer = (void (*)(void))(long) restorer;
 		siginitset(&new_ka.sa.sa_mask, mask);
 	}
 
@@ -171,9 +169,6 @@
 		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
-	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -188,15 +183,11 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-		
 	set_fs (KERNEL_DS);
 	ret = sys_sigpending(&s);
 	set_fs (old_fs);
 	if (put_user (s, set)) return -EFAULT;
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	return ret;
 }
 
@@ -216,16 +207,12 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-	
 	if (set && get_user(s, set))
 		return -EFAULT;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
 	set_fs (old_fs);
 	
-	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
-
 	if (ret)
 		return ret;
 	if (oset && put_user (s, oset))
@@ -256,14 +243,10 @@
 {
 	struct sigcontext32 *sc, sigctx;
 	struct sigregs32 *sr;
-	int ret;
 	elf_gregset_t32 saved_regs;  /* an array of ELF_NGREG unsigned ints (32 bits) */
 	sigset_t set;
-	unsigned int prevsp;
 	int i;
 
-	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	sc = (struct sigcontext32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
@@ -279,107 +262,67 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	sc++;			/* Look at next sigcontext */
-	/* If the next sigcontext is actually the sigregs (frame)  */
-	/*   - then no more sigcontexts on the user stack          */  
-	if (sc == (struct sigcontext32*)(u64)sigctx.regs)
-	{
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs32*)(u64)sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		/* 
-		 * Copy the 32 bit register values off the user stack
-		 * into the 32 bit register area
-		 */
-		if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
-			goto badframe;
-		/*
-		 * The saved reg structure in the frame is an elf_grepset_t32,
-		 * it is a 32 bit register save of the registers in the
-		 * pt_regs structure that was stored on the kernel stack
-		 * during the system call when the system call was interrupted
-		 * for the signal. Only 32 bits are saved because the
-		 * sigcontext contains a pointer to the regs and the sig
-		 * context address is passed as a pointer to the signal
-		 * handler.  
-		 *
-		 * The entries in the elf_grepset have the same index as the
-		 * elements in the pt_regs structure.
-		 */
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		/*
-		 * Register 2 is the kernel toc - should be reset on
-		 * any calls into the kernel 
-		 */
-		for (i = 0; i < 32; i++)
-			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
-
-		/*
-		 *  restore the non gpr registers 
-		 */
-		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-		/*
-		 * Insure that the interrupt mode is 64 bit, during 32 bit
-		 * execution. (This is necessary because we only saved
-		 * lower 32 bits of msr.)
-		 */
-		regs->msr = regs->msr | MSR_ISF;
-
-		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
-		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
-		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
-		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
-		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
-		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
-		/* regs->softe is left unchanged (like the MSR.EE bit) */
-		/******************************************************/
-		/* the DAR and the DSISR are only relevant during a   */
-		/*   data or instruction storage interrupt. The value */
-		/*   will be set to zero.                             */
-		/******************************************************/
-		regs->dar = 0; 
-		regs->dsisr = 0;
-		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+	sr = (struct sigregs32*)(u64)sigctx.regs;
+	/*
+	 * Copy the 32 bit register values off the user stack
+	 * into the 32 bit register area
+	 */
+	if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
+		goto badframe;
 
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs)))
-			goto badframe;
+	/*
+	 * The saved reg structure in the frame is an elf_grepset_t32,
+	 * it is a 32 bit register save of the registers in the
+	 * pt_regs structure that was stored on the kernel stack
+	 * during the system call when the system call was interrupted
+	 * for the signal. Only 32 bits are saved because the
+	 * sigcontext contains a pointer to the regs and the sig
+	 * context address is passed as a pointer to the signal
+	 * handler.  
+	 *
+	 * The entries in the elf_grepset have the same index as the
+	 * elements in the pt_regs structure.
+	 */
+	for (i = 0; i < 32; i++)
+		regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
 
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE32;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs32*)(u64)sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
+	/*
+	 *  restore the non gpr registers 
+	 */
+	regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
+	regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
+	regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
+	regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+	regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+	regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+	/* regs->softe is left unchanged (like the MSR.EE bit) */
+	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+	/* force the process to reload the FP registers from
+	   current->thread when it next does FP instructions */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
+		goto badframe;
 
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned int*) regs->gpr[1]))
-			goto badframe;
-		current->thread.fpscr = 0;
-	}
-  
-	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm);
-	return ret;
+	return regs->result;
 
 badframe:
-	PPCDBG(PPCDBG_SYS32NI, "sys32_sigreturn - badframe - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }	
 
 /*
  * Set up a signal frame.
  */
 static void
-setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
-            unsigned int newsp)
+setup_frame32(struct pt_regs *regs, int sig, struct k_sigaction *ka,
+	      struct sigregs32 *frame, unsigned int newsp)
 {
-	struct sigcontext32 *sc = (struct sigcontext32 *)(u64)newsp;
 	int i;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
@@ -425,30 +368,32 @@
 			   (unsigned long) &frame->tramp[2]);
 	current->thread.fpscr = 0;      /* turn off all fp exceptions */
 
-	newsp -= __SIGNAL_FRAMESIZE32;
-	if (put_user(regs->gpr[1], (u32*)(u64)newsp)
-	    || get_user(regs->nip, &sc->handler)
-	    || get_user(regs->gpr[3], &sc->signal))
-		goto badframe;
-
-	regs->gpr[1] = newsp & 0xFFFFFFFF;
 	/*
 	 * first parameter to the signal handler is the signal number
 	 *  - the value is in gpr3
 	 * second parameter to the signal handler is the sigcontext
 	 *   - set the value into gpr4
 	 */
-	regs->gpr[4] = (unsigned long) sc;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = newsp;
+	regs->nip = (u64)ka->sa.sa_handler & 0xFFFFFFFF;
 	regs->link = (unsigned long) frame->tramp;
+
+	newsp -= __SIGNAL_FRAMESIZE32;
+	if (put_user(regs->gpr[1], (u32*)(u64)newsp))
+		goto badframe;
+	regs->gpr[1] = newsp;
+
 	return;
 
  badframe:
-	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
 #if DEBUG_SIG
 	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -485,14 +430,12 @@
 	struct sigcontext32 sigctx;
 	struct sigregs32 *signalregs;
  
-	int i, ret;
+	int i;
 	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
 	sigset_t signal_set; 
 	stack_t stack;
-	unsigned int previous_stack;
 
-	ret = 0;
-	/* Adjust the inputted reg1 to point to the first rt signal frame */
+	/* Adjust the inputted reg1 to point to the rt signal frame */
 	rt_stack_frame = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	/* Copy the information from the user stack  */
 	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
@@ -514,100 +457,54 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	/* Set to point to the next rt_sigframe - this is used to determine whether this 
-	 *   is the last signal to process
-	 */
-	rt_stack_frame ++;
-
-	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs)) {
-		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
-		/* If currently owning the floating point - give them up */
-		if (regs->msr & MSR_FP)
-			giveup_fpu(current);
+	signalregs = (struct sigregs32 *) (u64)sigctx.regs;
 
-		if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) 
-			goto badframe;
-
-		/*
-		 * The saved reg structure in the frame is an elf_grepset_t32,
-		 * it is a 32 bit register save of the registers in the
-		 * pt_regs structure that was stored on the kernel stack
-		 * during the system call when the system call was interrupted
-		 * for the signal. Only 32 bits are saved because the
-		 * sigcontext contains a pointer to the regs and the sig
-		 * context address is passed as a pointer to the signal handler
-		 *
-		 * The entries in the elf_grepset have the same index as
-		 * the elements in the pt_regs structure.
-		 */
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		/*
-		 * Register 2 is the kernel toc - should be reset on any
-		 * calls into the kernel
-		 */
-		for (i = 0; i < 32; i++)
-			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
-		/*
-		 * restore the non gpr registers
-		 */
-		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
-		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
-		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
-		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
-		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
-		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
-		/* regs->softe is left unchanged (like MSR.EE) */
-		/*
-		 * the DAR and the DSISR are only relevant during a
-		 *   data or instruction storage interrupt. The value
-		 *   will be set to zero.
-		 */
-		regs->dar = 0; 
-		regs->dsisr = 0;
-		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
-
-		if (copy_from_user(current->thread.fpr, &signalregs->fp_regs, sizeof(signalregs->fp_regs))) 
-			goto badframe;
-
-		ret = regs->result;
-	}
-	else  /* more signals to go  */
-	{
-		regs->gpr[1] = (u64)rt_stack_frame - __SIGNAL_FRAMESIZE32;
-		if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx)))
-		{
-			goto badframe;
-		}
-		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
-		/* first parm to signal handler is the signal number */
-		regs->gpr[3] = ret = sigctx.signal;
-		/* second parm is a pointer to sig info */
-		get_user(regs->gpr[4], &rt_stack_frame->pinfo);
-		/* third parm is a pointer to the ucontext */
-		get_user(regs->gpr[5], &rt_stack_frame->puc);
-		/* fourth parm is the stack frame */
-		regs->gpr[6] = (u64)rt_stack_frame;
-		/* Set up link register to return to sigreturn when the */
-		/*  signal handler completes */
-		regs->link = (u64)&signalregs->tramp;
-		/* Set next instruction to the start fo the signal handler */
-		regs->nip = sigctx.handler;
-		/* Set the reg1 to look like a call to the signal handler */
-		if (get_user(previous_stack,&signalregs->gp_regs[PT_R1])
-		    || put_user(previous_stack, (unsigned long *)regs->gpr[1]))
-		{
-			goto badframe;
-		}
-		current->thread.fpscr = 0;
+	if (copy_from_user(saved_regs, &signalregs->gp_regs,
+			   sizeof(signalregs->gp_regs))) 
+		goto badframe;
 
-	}
+	/*
+	 * The saved reg structure in the frame is an elf_grepset_t32,
+	 * it is a 32 bit register save of the registers in the
+	 * pt_regs structure that was stored on the kernel stack
+	 * during the system call when the system call was interrupted
+	 * for the signal. Only 32 bits are saved because the
+	 * sigcontext contains a pointer to the regs and the sig
+	 * context address is passed as a pointer to the signal handler
+	 *
+	 * The entries in the elf_grepset have the same index as
+	 * the elements in the pt_regs structure.
+	 */
+	for (i = 0; i < 32; i++)
+		regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+	/*
+	 * restore the non gpr registers
+	 */
+	regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
+	regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
+	regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
+	regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+	regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+	regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+	/* regs->softe is left unchanged (like MSR.EE) */
+	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+	/* force the process to reload the FP registers from
+	   current->thread when it next does FP instructions */
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+#ifndef CONFIG_SMP
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+#endif
+	if (copy_from_user(current->thread.fpr, &signalregs->fp_regs,
+			   sizeof(signalregs->fp_regs))) 
+		goto badframe;
 
-	return ret;
+	return regs->result;
 
  badframe:
-	do_exit(SIGSEGV);     
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 
@@ -617,15 +514,14 @@
 	struct k_sigaction new_ka, old_ka;
 	int ret;
 	sigset32_t set32;
-
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - entered - sig=%x \n", sig);
+	u32 handler;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset32_t))
 		return -EINVAL;
 
 	if (act) {
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret = get_user(handler, &act->sa_handler);
 		ret |= __copy_from_user(&set32, &act->sa_mask,
 					sizeof(sigset32_t));
 		switch (_NSIG_WORDS) {
@@ -643,6 +539,7 @@
 		
 		if (ret)
 			return -EFAULT;
+		new_ka.sa.sa_handler = (__sighandler_t)(long) handler;
 	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
@@ -668,9 +565,7 @@
 		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 	}
 
-  
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - exiting - sig=%x \n", sig);
-	return ret;
+  	return ret;
 }
 
 
@@ -691,8 +586,6 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigprocmask - entered how=%x \n", (int)how);
-	
 	if (set) {
 		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
 			return -EFAULT;
@@ -779,7 +672,7 @@
 	case SIGBUS:
 	case SIGFPE:
 	case SIGILL:
-		d->si_addr = (unsigned int)(s->si_addr);
+		d->si_addr = (unsigned int)(u64)(s->si_addr);
         break;
 	case SIGPOLL:
 		d->si_band = s->si_band;
@@ -943,7 +836,7 @@
 	regs->gpr[3] = EINTR;
 	regs->ccr |= 0x10000000;
 	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 		if (do_signal(&saveset, regs))
 			/*
@@ -963,10 +856,9 @@
  * Set up a rt signal frame.
  */
 static void
-setup_rt_frame32(struct pt_regs *regs, struct sigregs32 *frame,
-            unsigned int newsp)
+setup_rt_frame32(struct pt_regs *regs, int sig, struct k_sigaction *ka,
+		 struct sigregs32 *frame, unsigned int newsp)
 {
-	unsigned int copyreg4,copyreg5;
 	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
 	int i;
   
@@ -1013,34 +905,31 @@
 	current->thread.fpscr = 0;	/* turn off all fp exceptions */
   
 	/*
-	 * Retrieve rt_sigframe from stack and
-	 * set up registers for signal handler
-	*/
+	 * Set up registers for signal handler
+	 */
 	newsp -= __SIGNAL_FRAMESIZE32;
-      
-
-	if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp)
-	    || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(copyreg4, &rt_sf->pinfo)
-	    || get_user(copyreg5, &rt_sf->puc))
-		goto badframe;
 
-	regs->gpr[4] = copyreg4;
-	regs->gpr[5] = copyreg5;
 	regs->gpr[1] = newsp;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = (unsigned long) &rt_sf->info;
+	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->link = (unsigned long) frame->tramp;
+	regs->nip    = (unsigned long) ka->sa.sa_handler;
+	regs->link   = (unsigned long) frame->tramp;
+
+	if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp))
+		goto badframe;
 
 	return;
 
  badframe:
-	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
 #if DEBUG_SIG
-	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
+	printk("badframe in setup_rt_frame32, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -1131,7 +1020,9 @@
 	       regs, frame, *newspp);
 	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -1150,6 +1041,8 @@
 	int ret;
 	mm_segment_t old_fs;
 	unsigned long sp;
+	u32 sssp;
+	stack_32_t *ustack;
 
 	/*
 	 * set sp to the user stack on entry to the system call
@@ -1157,21 +1050,26 @@
 	 */
 	sp = regs->gpr[1];
 
-	/*  Put new stack info in local 64 bit stack struct                      */ 
-	if (newstack && (get_user((long)uss.ss_sp, &((stack_32_t *)(long)newstack)->ss_sp) ||
-			 __get_user(uss.ss_flags, &((stack_32_t *)(long)newstack)->ss_flags) ||
-			 __get_user(uss.ss_size, &((stack_32_t *)(long)newstack)->ss_size)))
+	/*  Put new stack info in local 64 bit stack struct */ 
+	ustack = (stack_32_t *)(long) newstack;
+	if (newstack && (get_user(sssp, &ustack->ss_sp) ||
+			 __get_user(uss.ss_flags, &ustack->ss_flags) ||
+			 __get_user(uss.ss_size, &ustack->ss_size)))
 		return -EFAULT; 
-
+	uss.ss_sp = (void *)(long) sssp;
    
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = do_sigaltstack(newstack ? &uss : NULL, oldstack ? &uoss : NULL, sp);
 	set_fs(old_fs);
-	/* Copy the stack information to the user output buffer                  */
-	if (!ret && oldstack  && (put_user((long)uoss.ss_sp, &((stack_32_t *)(long)oldstack)->ss_sp) ||
-				  __put_user(uoss.ss_flags, &((stack_32_t *)(long)oldstack)->ss_flags) ||
-				  __put_user(uoss.ss_size, &((stack_32_t *)(long)oldstack)->ss_size)))
+	if (ret)
+		return ret;
+
+	/* Copy the stack information to the user output buffer */
+	ustack = (stack_32_t *)(long) oldstack;
+	if (oldstack && (put_user((long)uoss.ss_sp, &ustack->ss_sp) ||
+			 __put_user(uoss.ss_flags, &ustack->ss_flags) ||
+			 __put_user(uoss.ss_size, &ustack->ss_size)))
 		return -EFAULT;
 	return ret;
 }
@@ -1198,6 +1096,7 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 	unsigned int frame, newsp;
+	unsigned long signr = 0;
 
 	if (!oldset)
 		oldset = &current->blocked;
@@ -1205,15 +1104,9 @@
 	newsp = frame = 0;
 
 	for (;;) {
-		unsigned long signr;
-		
 		spin_lock_irq(&current->sigmask_lock);
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
-		ifppcdebug(PPCDBG_SYS32) {
-			if (signr)
-				udbg_printf("do_signal32 - processing signal=%2lx - pid=%ld, comm=%s \n", signr, current->pid, current->comm);
-		}
 
 		if (!signr)
 			break;
@@ -1298,14 +1191,6 @@
 			}
 		}
 
-		PPCDBG(PPCDBG_SIGNAL, " do signal :sigaction flags = %lx \n" ,ka->sa.sa_flags);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :on sig stack  = %lx \n" ,on_sig_stack(regs->gpr[1]));
-		PPCDBG(PPCDBG_SIGNAL, " do signal :reg1  = %lx \n" ,regs->gpr[1]);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack  = %lx \n" ,current->sas_ss_sp);
-		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack size  = %lx \n" ,current->sas_ss_size);
-
-
-
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
@@ -1333,8 +1218,10 @@
 
 	/* Invoke correct stack setup routine */
 	if (ka->sa.sa_flags & SA_SIGINFO) 
-		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+		setup_rt_frame32(regs, signr, ka,
+				 (struct sigregs32*)(u64)frame, newsp);
 	else
-		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+		setup_frame32(regs, signr, ka,
+			      (struct sigregs32*)(u64)frame, newsp);
 	return 1;
 }
diff -urN linux-2.4.29-pre3/arch/sparc64/kernel/binfmt_aout32.c linux-2.4.29-rc1/arch/sparc64/kernel/binfmt_aout32.c
--- linux-2.4.29-pre3/arch/sparc64/kernel/binfmt_aout32.c	2002-08-02 17:39:43.000000000 -0700
+++ linux-2.4.29-rc1/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 10:54:50.022654016 -0800
@@ -49,7 +49,7 @@
 	end = PAGE_ALIGN(end);
 	if (end <= start)
 		return;
-	do_brk(start, end - start);
+	do_brk_locked(start, end - start);
 }
 
 /*
@@ -246,10 +246,10 @@
 	if (N_MAGIC(ex) == NMAGIC) {
 		loff_t pos = fd_offset;
 		/* Fuck me plenty... */
-		error = do_brk(N_TXTADDR(ex), ex.a_text);
+		error = do_brk_locked(N_TXTADDR(ex), ex.a_text);
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text, &pos);
-		error = do_brk(N_DATADDR(ex), ex.a_data);
+		error = do_brk_locked(N_DATADDR(ex), ex.a_data);
 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
 			  ex.a_data, &pos);
 		goto beyond_if;
@@ -257,7 +257,7 @@
 
 	if (N_MAGIC(ex) == OMAGIC) {
 		loff_t pos = fd_offset;
-		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+		do_brk_locked(N_TXTADDR(ex) & PAGE_MASK,
 			ex.a_text+ex.a_data + PAGE_SIZE - 1);
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text+ex.a_data, &pos);
@@ -272,7 +272,7 @@
 
 		if (!bprm->file->f_op->mmap) {
 			loff_t pos = fd_offset;
-			do_brk(0, ex.a_text+ex.a_data);
+			do_brk_locked(0, ex.a_text+ex.a_data);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 				  ex.a_text+ex.a_data, &pos);
 			goto beyond_if;
@@ -388,7 +388,7 @@
 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len) {
-		error = do_brk(start_addr + len, bss - len);
+		error = do_brk_locked(start_addr + len, bss - len);
 		retval = error;
 		if (error != start_addr + len)
 			goto out;
diff -urN linux-2.4.29-pre3/arch/sparc64/kernel/ioctl32.c linux-2.4.29-rc1/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.29-pre3/arch/sparc64/kernel/ioctl32.c	2005-01-12 10:54:46.673510092 -0800
+++ linux-2.4.29-rc1/arch/sparc64/kernel/ioctl32.c	2005-01-12 10:54:50.026654188 -0800
@@ -4918,6 +4918,10 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
diff -urN linux-2.4.29-pre3/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.29-rc1/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.29-pre3/arch/x86_64/ia32/ia32_ioctl.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/arch/x86_64/ia32/ia32_ioctl.c	2005-01-12 10:54:50.034654532 -0800
@@ -4099,6 +4099,10 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
diff -urN linux-2.4.29-pre3/arch/x86_64/ia32/ptrace32.c linux-2.4.29-rc1/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.29-pre3/arch/x86_64/ia32/ptrace32.c	2004-04-14 06:05:28.000000000 -0700
+++ linux-2.4.29-rc1/arch/x86_64/ia32/ptrace32.c	2005-01-12 10:54:50.036654618 -0800
@@ -185,12 +185,12 @@
 			goto out;
 		*err = ptrace_check_attach(child, request == PTRACE_KILL); 
 		if (*err < 0) 
-				goto out;
+			goto out;
 		return child; 
-	} 
 
  out:
-	free_task_struct(child);
+		free_task_struct(child);
+	} 
 	return NULL; 
 	
 } 
diff -urN linux-2.4.29-pre3/drivers/char/ip2/i2ellis.c linux-2.4.29-rc1/drivers/char/ip2/i2ellis.c
--- linux-2.4.29-pre3/drivers/char/ip2/i2ellis.c	2001-10-24 12:05:18.000000000 -0700
+++ linux-2.4.29-rc1/drivers/char/ip2/i2ellis.c	2005-01-12 10:54:50.074656251 -0800
@@ -605,7 +605,7 @@
 
 	set_current_state( TASK_INTERRUPTIBLE );
 
-	pDelayTimer->expires  = jiffies + ( mseconds + 9 ) / 10;
+	pDelayTimer->expires  = jiffies + ((HZ * mseconds + 999) / 1000);
 	pDelayTimer->function = ii2DelayWakeup;
 	pDelayTimer->data     = 0;
 
diff -urN linux-2.4.29-pre3/drivers/char/ip2/i2ellis.h linux-2.4.29-rc1/drivers/char/ip2/i2ellis.h
--- linux-2.4.29-pre3/drivers/char/ip2/i2ellis.h	2001-10-24 12:05:18.000000000 -0700
+++ linux-2.4.29-rc1/drivers/char/ip2/i2ellis.h	2005-01-12 10:54:50.075656294 -0800
@@ -403,7 +403,6 @@
 //	For queuing interupt bottom half handlers.	/\/\|=mhw=|\/\/
 	struct tq_struct	tqueue_interrupt;
 
-	struct timer_list  SendPendingTimer;   // Used by iiSendPending
 	unsigned int	SendPendingRetry;
 
 #ifdef	CONFIG_DEVFS_FS
diff -urN linux-2.4.29-pre3/drivers/char/ip2/i2lib.c linux-2.4.29-rc1/drivers/char/ip2/i2lib.c
--- linux-2.4.29-pre3/drivers/char/ip2/i2lib.c	2005-01-12 10:54:46.767514132 -0800
+++ linux-2.4.29-rc1/drivers/char/ip2/i2lib.c	2005-01-12 10:54:50.077656380 -0800
@@ -174,8 +174,12 @@
 			pB->i2eWaitingForEmptyFifo |=
 				(pB->i2eOutMailWaiting & MB_OUT_STUFFED);
 			pB->i2eOutMailWaiting = 0;
+			if( pB->SendPendingRetry ) {
+				printk( KERN_DEBUG "IP2: iiSendPendingMail: busy board pickup on %d\n", pB->SendPendingRetry );
+			}
 			pB->SendPendingRetry = 0;
 		} else {
+#ifdef	IP2_USE_TIMER_WAIT
 /*		The only time we hit this area is when "iiTrySendMail" has
 		failed.  That only occurs when the outbound mailbox is
 		still busy with the last message.  We take a short breather
@@ -193,6 +197,11 @@
 			} else {
 				printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" );
 			}
+#endif
+			pB->SendPendingRetry++;
+			if( 0 == ( pB->SendPendingRetry % 8 ) ) {
+				printk( KERN_ERR "IP2: iiSendPendingMail: board busy, retry %d\n", pB->SendPendingRetry );
+			}
 		}
 	}
 }
@@ -1329,8 +1338,9 @@
 	remove_wait_queue(&(pCh->pBookmarkWait), &wait);
 
 	// if expires == 0 then timer poped, then do not need to del_timer
+	// jiffy wrap per Tim Schmielau (tim@physik3.uni-rostock.de)
 	if ((timeout > 0) && pCh->BookmarkTimer.expires && 
-	                     time_before(jiffies, pCh->BookmarkTimer.expires)) {
+			time_before(jiffies, pCh->BookmarkTimer.expires)) {
 		del_timer( &(pCh->BookmarkTimer) );
 		pCh->BookmarkTimer.expires = 0;
 
diff -urN linux-2.4.29-pre3/drivers/char/ip2/ip2types.h linux-2.4.29-rc1/drivers/char/ip2/ip2types.h
--- linux-2.4.29-pre3/drivers/char/ip2/ip2types.h	1999-08-23 10:23:23.000000000 -0700
+++ linux-2.4.29-rc1/drivers/char/ip2/ip2types.h	2005-01-12 10:54:50.077656380 -0800
@@ -49,6 +49,10 @@
 	short irq[IP2_MAX_BOARDS]; 
 	unsigned short addr[IP2_MAX_BOARDS];
 	int type[IP2_MAX_BOARDS];
+#ifdef CONFIG_PCI
+	struct pci_dev *pci_dev[IP2_MAX_BOARDS];
+#endif
+
 } ip2config_t;
 
 #endif
diff -urN linux-2.4.29-pre3/drivers/char/ip2main.c linux-2.4.29-rc1/drivers/char/ip2main.c
--- linux-2.4.29-pre3/drivers/char/ip2main.c	2005-01-12 10:54:46.770514261 -0800
+++ linux-2.4.29-rc1/drivers/char/ip2main.c	2005-01-12 10:54:50.080656508 -0800
@@ -19,6 +19,26 @@
 //
 // Done:
 //
+// 1.2.18	/\/\|=mhw=|\/\/
+// Fixed jiffies math in ii2DelayTimer...
+//	How long has THIS been broken?  Delay was basically a noop...
+// Dumped some groady tracing code that hasn't been used (or tested) in
+//	years and was only a source of warning messages.
+//
+// 1.2.17	/\/\|=mhw=|\/\/
+// PCI fixes submitted by Bjorn Helgaas
+//	Added calls to Add pci_enable_device()/pci_disable_device() per
+//	submitted patches.  My thanks to Bjorn Helgaas <bjorn.helgaas@hp.com>.
+//
+// 1.2.16	/\/\|=mhw=|\/\/
+// Yet another shot at the busy board timing window (use the poll timer).
+// 	Because of this, the poll timer is always enabled...
+// Cleaned up some comments on immediate interrupt mode (ppp code elsewhere
+// 	has been fixed and the new busy board logic won't throw a hairball).
+//
+// 1.2.15	dmc
+// Fixed jiffy wrap, PCI card may now be set to poll.
+//
 // 1.2.14	/\/\|=mhw=|\/\/
 // Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
 // Changed the definition of ip2trace to be more consistant with kernel style
@@ -227,7 +247,7 @@
 
 /* String constants to identify ourselves */
 static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static char *pcVersion = "1.2.18";
 
 /* String constants for port names */
 static char *pcDriver_name   = "ip2";
@@ -437,7 +457,7 @@
 	}
 	return 0;
 }
-#endif
+#endif /* MODULE */
 
 static int __init
 have_requested_irq( char irq )
@@ -545,6 +565,12 @@
 	// free memory
 	for (i = 0; i < IP2_MAX_BOARDS; i++) {
 		void *pB;
+#ifdef CONFIG_PCI
+		if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
+			pci_disable_device(ip2config.pci_dev[i]);
+			ip2config.pci_dev[i] = NULL;
+		}
+#endif
 		if ((pB = i2BoardPtrTable[i]) != 0 ) {
 			kfree ( pB );
 			i2BoardPtrTable[i] = NULL;
@@ -604,17 +630,12 @@
 		if (iop) {
 			ip2config.addr[i] = iop[i];
 			if (irqp) {
-				if( irqp[i] >= 0 ) {
-					ip2config.irq[i] = irqp[i];
-				} else {
-					ip2config.irq[i] = 0;
-				}
+				ip2config.irq[i] = irqp[i];
 	// This is a little bit of a hack.  If poll_only=1 on command
 	// line back in ip2.c OR all IRQs on all specified boards are
 	// explicitly set to 0, then drop to poll only mode and override
 	// PCI or EISA interrupts.  This superceeds the old hack of
 	// triggering if all interrupts were zero (like da default).
-	// Still a hack but less prone to random acts of terrorism.
 	//
 	// What we really should do, now that the IRQ default is set
 	// to -1, is to use 0 as a hard coded, do not probe.
@@ -700,17 +721,12 @@
 					} else {
 						printk( KERN_ERR "IP2: PCI I/O address error\n");
 					}
-					pcibios_read_config_byte(pci_bus, pci_devfn,
+					if (ip2config.irq[i] != 0) {
+						pcibios_read_config_byte(pci_bus, pci_devfn,
 								  PCI_INTERRUPT_LINE, &pci_irq);
 
-//		If the PCI BIOS assigned it, lets try and use it.  If we
-//		can't acquire it or it screws up, deal with it then.
-
-//					if (!is_valid_irq(pci_irq)) {
-//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//						pci_irq = 0;
-//					}
-					ip2config.irq[i] = pci_irq;
+						ip2config.irq[i] = pci_irq;
+					}
 				} else {	// ann error
 					ip2config.addr[i] = 0;
 					if (status == PCIBIOS_DEVICE_NOT_FOUND) {
@@ -727,9 +743,15 @@
 							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
 				if (pci_dev_i != NULL) {
 					unsigned int addr;
-					unsigned char pci_irq;
+
+					if (pci_enable_device(pci_dev_i)) {
+						printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
+						pci_name(pci_dev_i));
+						break;
+					}
 
 					ip2config.type[i] = PCI;
+					ip2config.pci_dev[i] = pci_dev_i;
 					status =
 					pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
 					if ( addr & 1 ) {
@@ -737,18 +759,8 @@
 					} else {
 						printk( KERN_ERR "IP2: PCI I/O address error\n");
 					}
-					status =
-					pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
-
-//		If the PCI BIOS assigned it, lets try and use it.  If we
-//		can't acquire it or it screws up, deal with it then.
-
-//					if (!is_valid_irq(pci_irq)) {
-//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//						pci_irq = 0;
-//					}
-					ip2config.irq[i] = pci_irq;
-				} else {	// ann error
+					ip2config.irq[i] = pci_dev_i->irq;
+				} else {	// an error
 					ip2config.addr[i] = 0;
 					if (status == PCIBIOS_DEVICE_NOT_FOUND) {
 						printk( KERN_ERR "IP2: PCI board %d not found\n", i );
@@ -964,6 +976,14 @@
 				/* Initialise the interrupt handler bottom half (aka slih). */
 			}
 		}
+
+		if (!TimerOn) {
+//			Kick the timer on for stuck board safeties...
+			PollTimer.expires = POLL_TIMEOUT;
+			add_timer ( &PollTimer );
+			TimerOn = 1;
+		}
+
 		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
 			if ( i2BoardPtrTable[i] ) {
 				set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
@@ -1375,8 +1395,10 @@
 
 //		Only process those boards which match our IRQ.
 //			IRQ = 0 for polled boards, we won't poll "IRQ" boards
+//		Add an additional "check" if the irq is zero for boards
+//		which are "stuck"
 
-		if ( pB && (pB->i2eUsingIrq == irq) ) {
+		if ( pB && ( pB->i2eUsingIrq == irq || ( 0 == irq && 0 != pB->SendPendingRetry ) ) ) {
 #ifdef USE_IQI
 
 		    if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
@@ -1391,9 +1413,8 @@
 			mark_bh(IMMEDIATE_BH);
 		    }
 #else
-//		We are using immediate servicing here.  This sucks and can
-//		cause all sorts of havoc with ppp and others.  The failsafe
-//		check on iiSendPendingMail could also throw a hairball.
+//		We are using immediate servicing here.  Suboptimal
+//			to say the least...
 			i2ServiceBoard( pB );
 #endif /* USE_IQI */
 		}
@@ -1417,6 +1438,9 @@
 static void
 ip2_poll(unsigned long arg)
 {
+	int i;
+	i2eBordStrPtr  pB;
+
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
 	TimerOn = 0; // it's the truth but not checked in service
@@ -1424,7 +1448,15 @@
 	// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
 	// It will NOT poll boards handled by hard interrupts.
 	// The issue of queued BH interrups is handled in ip2_interrupt().
-	ip2_interrupt(0, NULL, NULL);
+
+	for( i = 0; i < i2nBoards; ++i ) {
+		pB = i2BoardPtrTable[i];
+	// Service the board if the irq indicates a polled board
+	// OR if the SendPendingRetry indicates a retry state in the board
+		if ( pB && ( 0 == pB->i2eUsingIrq || 0 != pB->SendPendingRetry ) ) {
+			i2ServiceBoard( pB );
+		}
+	}
 
 	PollTimer.expires = POLL_TIMEOUT;
 	add_timer( &PollTimer );
@@ -3196,7 +3228,16 @@
 	case 2:	    // Ping device
 		rc = -EINVAL;
 		break;
+
+#ifdef IP2_TRACE_DEVICE
 	case 3:	    // Trace device
+/*
+	This may have been useful at one time during early development
+	but has not been used for years and is just a source of excess
+	baggage and unused code and warnings.  The client programs that
+	understood this returned "blob" don't even currently compile...
+	Disabled until needed in the future.  /\/\|=mhw=|\/\/  12/22/2004
+*/
 		if ( cmd == 1 ) {
 			PUT_USER(rc, iiSendPendingMail, pIndex++ );
 			PUT_USER(rc, i2InitChannels, pIndex++ );
@@ -3257,6 +3298,7 @@
 		}
 
 		break;
+#endif
 
 	default:
 		rc = -ENODEV;
diff -urN linux-2.4.29-pre3/drivers/media/video/bttv-if.c linux-2.4.29-rc1/drivers/media/video/bttv-if.c
--- linux-2.4.29-pre3/drivers/media/video/bttv-if.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29-rc1/drivers/media/video/bttv-if.c	2005-01-12 10:54:50.243663513 -0800
@@ -190,7 +190,6 @@
 	return state;
 }
 
-#ifndef I2C_PEC
 static void bttv_inc_use(struct i2c_adapter *adap)
 {
 	MOD_INC_USE_COUNT;
@@ -200,7 +199,6 @@
 {
 	MOD_DEC_USE_COUNT;
 }
-#endif
 
 static int attach_inform(struct i2c_client *client)
 {
@@ -243,12 +241,8 @@
 };
 
 static struct i2c_adapter bttv_i2c_adap_template = {
-#ifdef I2C_PEC
-	.owner             = THIS_MODULE,
-#else
 	.inc_use           = bttv_inc_use,
 	.dec_use           = bttv_dec_use,
-#endif
 #ifdef I2C_ADAP_CLASS_TV_ANALOG
 	.class             = I2C_ADAP_CLASS_TV_ANALOG,
 #endif
diff -urN linux-2.4.29-pre3/drivers/media/video/tvmixer.c linux-2.4.29-rc1/drivers/media/video/tvmixer.c
--- linux-2.4.29-pre3/drivers/media/video/tvmixer.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.29-rc1/drivers/media/video/tvmixer.c	2005-01-12 10:54:50.243663513 -0800
@@ -193,10 +193,8 @@
 
 	/* lock bttv in memory while the mixer is in use  */
 	file->private_data = mix;
-#ifndef I2C_PEC
 	if (client->adapter->inc_use)
 		client->adapter->inc_use(client->adapter);
-#endif
         return 0;
 }
 
@@ -210,17 +208,12 @@
 		return -ENODEV;
 	}
 
-#ifndef I2C_PEC
 	if (client->adapter->dec_use)
 		client->adapter->dec_use(client->adapter);
-#endif
 	return 0;
 }
 
 static struct i2c_driver driver = {
-#ifdef I2C_PEC
-	.owner           = THIS_MODULE,
-#endif
 	.name            = "tv card mixer driver",
         .id              = I2C_DRIVERID_TVMIXER,
 #ifdef I2C_DF_DUMMY
diff -urN linux-2.4.29-pre3/drivers/net/8139cp.c linux-2.4.29-rc1/drivers/net/8139cp.c
--- linux-2.4.29-pre3/drivers/net/8139cp.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/8139cp.c	2005-01-12 10:54:50.251663857 -0800
@@ -398,6 +398,8 @@
 static struct pci_device_id cp_pci_tbl[] = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
 	{ },
 };
 MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
diff -urN linux-2.4.29-pre3/drivers/net/8390.c linux-2.4.29-rc1/drivers/net/8390.c
--- linux-2.4.29-pre3/drivers/net/8390.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/8390.c	2005-01-12 10:54:50.253663943 -0800
@@ -1143,7 +1143,7 @@
    
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
     
-	if (inb_p(e8390_base) & E8390_TRANS) 
+	if (inb_p(e8390_base+E8390_CMD) & E8390_TRANS) 
 	{
 		printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
 			dev->name);
diff -urN linux-2.4.29-pre3/drivers/net/Config.in linux-2.4.29-rc1/drivers/net/Config.in
--- linux-2.4.29-pre3/drivers/net/Config.in	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/Config.in	2005-01-12 10:54:50.253663943 -0800
@@ -71,9 +71,6 @@
          bool '   Broadcom 5222 Dual Phy Support' CONFIG_BCM5222_DUAL_PHY
       fi
    fi
-   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
@@ -272,6 +269,9 @@
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'Realtek 8169 Gigabit Ethernet support' CONFIG_R8169 $CONFIG_PCI
+if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+   tristate 'SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
+fi
 dep_tristate 'Marvell Yukon Chipset / SysKonnect SK-98xx Support' CONFIG_SK98LIN $CONFIG_PCI
 dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI
 
@@ -281,6 +281,13 @@
    dep_bool '    MV-64340 Port 1' CONFIG_MV64340_ETH_1 $CONFIG_MV64340_ETH
    dep_bool '    MV-64340 Port 2' CONFIG_MV64340_ETH_2 $CONFIG_MV64340_ETH
 fi
+
+if [ "$CONFIG_PMC_BIG_SUR" = "y" ]; then
+   tristate 'PMC-Sierra Big Sur Fast Ethernet Adapter' CONFIG_BIG_SUR_FE
+fi
+if [ "$CONFIG_PMC_YOSEMITE" = "y" ]; then
+   tristate 'PMC-Sierra TITAN Gigabit Ethernet Support' CONFIG_TITAN_GE
+fi
 endmenu
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
@@ -293,8 +300,8 @@
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-   if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
-      tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   if [ "$CONFIG_TC" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+      tristate '  Digital DEFTA/DEFEA/DEFPA adapter support' CONFIG_DEFXX
    fi
    dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
 fi
diff -urN linux-2.4.29-pre3/drivers/net/Makefile linux-2.4.29-rc1/drivers/net/Makefile
--- linux-2.4.29-pre3/drivers/net/Makefile	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/Makefile	2005-01-12 10:54:50.254663986 -0800
@@ -117,6 +117,8 @@
 
 obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
 obj-$(CONFIG_MV64340_ETH)	+= mv64340_eth.o
+obj-$(CONFIG_BIG_SUR_FE)	+= big_sur_ge.o
+obj-$(CONFIG_TITAN_GE)		+= titan_mdio.o titan_ge.o
 obj-$(CONFIG_AIRONET4500) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_CS) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_NONCS)  += aironet4500_card.o
diff -urN linux-2.4.29-pre3/drivers/net/au1000_eth.c linux-2.4.29-rc1/drivers/net/au1000_eth.c
--- linux-2.4.29-pre3/drivers/net/au1000_eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/au1000_eth.c	2005-01-12 10:54:50.255664029 -0800
@@ -241,7 +241,11 @@
 	mdelay(1);
 
 	/* set up LEDs to correct display */
+#ifdef CONFIG_MIPS_MTX1
+	mdio_write(dev, phy_addr, 17, 0xff80);
+#else
 	mdio_write(dev, phy_addr, 17, 0xffc0);
+#endif
 
 	if (au1000_debug > 4)
 		dump_mii(dev, phy_addr);
@@ -1077,6 +1081,7 @@
 static struct {
 	int port;
 	u32 base_addr;
+	u32 macen_addr;
 	int irq;
 	struct net_device *dev;
 } iflist[2];
@@ -1095,23 +1100,48 @@
 	struct net_device *dev;
 	int i, found_one = 0;
 
-	iflist[0].irq = AU1000_ETH0_IRQ;
-	iflist[1].irq = AU1000_ETH1_IRQ;
 	switch (c->cputype) {
+#ifdef CONFIG_SOC_AU1000
 	case CPU_AU1000:
 		num_ifs = 2 - ni;
 		iflist[0].base_addr = AU1000_ETH0_BASE;
 		iflist[1].base_addr = AU1000_ETH1_BASE;
+		iflist[0].macen_addr = AU1000_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1000_MAC1_ENABLE;
+		iflist[0].irq = AU1000_MAC0_DMA_INT;
+		iflist[1].irq = AU1000_MAC1_DMA_INT;
 		break;
+#endif
+#ifdef CONFIG_SOC_AU1100
 	case CPU_AU1100:
 		num_ifs = 1 - ni;
-		iflist[0].base_addr = AU1000_ETH0_BASE;
+		iflist[0].base_addr = AU1100_ETH0_BASE;
+		iflist[0].macen_addr = AU1100_MAC0_ENABLE;
+		iflist[0].irq = AU1100_MAC0_DMA_INT;
 		break;
+#endif
+#ifdef CONFIG_SOC_AU1500
 	case CPU_AU1500:
 		num_ifs = 2 - ni;
 		iflist[0].base_addr = AU1500_ETH0_BASE;
 		iflist[1].base_addr = AU1500_ETH1_BASE;
+		iflist[0].macen_addr = AU1500_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1500_MAC1_ENABLE;
+		iflist[0].irq = AU1500_MAC0_DMA_INT;
+		iflist[1].irq = AU1500_MAC1_DMA_INT;
+		break;
+#endif
+#ifdef CONFIG_SOC_AU1550
+	case CPU_AU1550:
+		num_ifs = 2 - ni;
+		iflist[0].base_addr = AU1550_ETH0_BASE;
+		iflist[1].base_addr = AU1550_ETH1_BASE;
+		iflist[0].macen_addr = AU1550_MAC0_ENABLE;
+		iflist[1].macen_addr = AU1550_MAC1_ENABLE;
+		iflist[0].irq = AU1550_MAC0_DMA_INT;
+		iflist[1].irq = AU1550_MAC1_DMA_INT;
 		break;
+#endif
 	default:
 		num_ifs = 0;
 	}
@@ -1173,9 +1203,8 @@
 	/* aup->mac is the base address of the MAC's registers */
 	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
 	/* Setup some variables for quick register address access */
-	switch (ioaddr) {
-	case AU1000_ETH0_BASE:
-	case AU1500_ETH0_BASE:
+	if (ioaddr == iflist[0].base_addr)
+	{
 		/* check env variables first */
 		if (!get_ethernet_addr(ethaddr)) { 
 			memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr));
@@ -1192,37 +1221,27 @@
 						sizeof(dev->dev_addr));
 			}
 		}
-		if (ioaddr == AU1000_ETH0_BASE)
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC0_ENABLE);
-		else
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC0_ENABLE);
+				((unsigned long)iflist[0].macen_addr);
 		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)
-			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1000_MAC1_ENABLE);
+	}
 		else
+	if (ioaddr == iflist[1].base_addr)
+	{
 			aup->enable = (volatile u32 *) 
-				((unsigned long)AU1500_MAC1_ENABLE);
+				((unsigned long)iflist[1].macen_addr);
 		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:
+	}
+	else
+	{
 		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
-		break;
-
 	}
 
 	/* bring the device out of reset, otherwise probing the mii
@@ -1370,6 +1389,7 @@
 		control |= MAC_FULL_DUPLEX;
 	}
 	aup->mac->control = control;
+	aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
 	au_sync();
 
 	spin_unlock_irqrestore(&aup->lock, flags);
diff -urN linux-2.4.29-pre3/drivers/net/big_sur_ge.c linux-2.4.29-rc1/drivers/net/big_sur_ge.c
--- linux-2.4.29-pre3/drivers/net/big_sur_ge.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/big_sur_ge.c	2005-01-12 10:54:50.258664158 -0800
@@ -0,0 +1,1613 @@
+/*
+ * drivers/net/big_sur_ge.c - Driver for PMC-Sierra Big Sur
+ * ethernet ports
+ *
+ * Copyright (C) 2003, 2004 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * This driver also includes the PHY related stuff. The device
+ * is a fast ethernet device. But, there is a Gigabit unit
+ * in the works. When that is ready, this driver will support
+ * it. 
+ *
+ * Basic Operation
+ * ================
+ * The device operates in following modes:
+ * -> Polled mode, no DMA (FIFO)
+ * -> Polled mode, Simple DMA
+ * -> Interrupt mode, Simple DMA
+ * -> Interrupt mode, Scatter Gather DMA
+ *
+ * Scatter Gather DMA does not work. So, we make use of Simple DMA
+ * mode here. There is no implementation of ring descriptors here
+ * since it is not working as yet. Note that there could be an enhancement
+ * whereby the driver can support FIFO mode or Simple DMA. However,
+ * this version only supports Simple DMA.
+ *
+ * Receive Operation
+ * ==================
+ * The device DMA's sends an interrupt to the processor. The driver 
+ * is invoked and it determines if the packet is to be received. If 
+ * yes, it allocates a new skb and has the DMA controller transfer the 
+ * data into the newly allocated skb. The receive side handles one 
+ * packet at a time. The Rx FIFO on the device is 2000 bytes.
+ *
+ * Send Operation
+ * ===============
+ * The device Transmit FIFO is 2000 bytes long, i.e. one packet. When
+ * sending, the driver makes sure that the packet is aligned. Once
+ * done, it asks the device to do a DMA transfer from memory to the 
+ * onboard FIFO. The device is stopped till the transfer completes since
+ * it can DMA only one packet at a time.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "big_sur_ge.h"
+
+MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>");
+MODULE_DESCRIPTION("PMC-Sierra Big Sur Ethernet MAC Driver");
+MODULE_LICENSE("GPL");
+
+#define TX_TIMEOUT (60 * HZ)      /* Transmit timeout */
+
+typedef enum DUPLEX { UNKNOWN, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
+
+/* Big Sur Ethernet MAC structure */
+struct big_sur_ge_enet {
+        struct net_device_stats *stats;	/* Statistics for this device */
+        struct timer_list phy_timer;    /* PHY monitoring timer */
+        u32 index;             		/* Which interface is this */
+        u32 save_base_address; 		/* Saved physical base address */
+        struct sk_buff *saved_skb;      /* skb being transmitted */
+        spinlock_t lock;            	/* For atomic access to saved_skb */
+        u8 mii_addr;        		/* The MII address of the PHY */
+        big_sur_ge *emac;               /* GE driver structure */
+	struct tasklet_struct big_sur_tasklet;	/* Tasklet structure */
+};
+
+extern unsigned char big_sur_mac_addr_base[6];
+
+/*
+ * Function Prototypes 
+ */
+unsigned long big_sur_ge_dma_control(xdma_channel *);
+void big_sur_ge_dma_reset(xdma_channel *);
+static void handle_intr(struct net_device *, big_sur_ge *);
+void big_sur_ge_check_fifo_recv_error(struct net_device *, big_sur_ge *);
+void big_sur_ge_check_fifo_send_error(struct net_device *, big_sur_ge *);
+static int big_sur_ge_config_fifo(big_sur_ge *);
+static int big_sur_ge_config_dma(big_sur_ge *);
+void big_sur_ge_enet_reset(big_sur_ge *);
+void big_sur_ge_check_mac_error(big_sur_ge *, unsigned long);
+static void big_sur_receive(struct net_device *);
+static void big_sur_tx_free_skb(struct net_device *);
+big_sur_ge_config *big_sur_ge_get_config(int);
+static void big_sur_ge_reset(struct net_device *,DUPLEX);
+
+/*
+ * DMA Channel Initialization. In case of Simple DMA,
+ * not much to do here. However, in case of SG DMA, we
+ * need to intialize the descriptor pointers 
+ */
+int big_sur_ge_dma_init(xdma_channel *dma, unsigned long base_address) 
+{
+	dma->reg_base_address = base_address;
+	dma->ready = 1; 
+
+	big_sur_ge_dma_reset(dma);
+	return 0;
+}
+
+/*
+ * Perform the self test on the DMA channel 
+ */
+#define BIG_SUR_GE_CONTROL_REG_RESET_MASK	0x98000000
+
+int big_sur_ge_dma_self_test(xdma_channel *dma)
+{
+	unsigned long	reg_data;
+
+	big_sur_ge_dma_reset(dma);
+	
+	reg_data = big_sur_ge_dma_control(dma);
+	if (reg_data != BIG_SUR_GE_CONTROL_REG_RESET_MASK) {
+		printk(KERN_ERR "DMA Channel Self Test Failed \n");
+		return -1;
+	}
+	
+	return 0;
+}
+
+/*
+ * Reset the DMA channel
+ */
+void big_sur_ge_dma_reset(xdma_channel *dma)
+{
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_RST_REG_OFFSET,
+						BIG_SUR_GE_RESET_MASK);
+}
+
+/*
+ * Get control register from the DMA channel
+ */
+unsigned long big_sur_ge_dma_control(xdma_channel *dma)
+{
+	return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET);
+}
+
+/*
+ * Set control register of the DMA channel
+ */
+void big_sur_ge_set_dma_control(xdma_channel *dma, unsigned long control)
+{
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET, control);
+}
+
+/*
+ * Get the status of the DMA channel 
+ */
+unsigned long big_sur_ge_dma_status(xdma_channel *dma)
+{
+	return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAS_REG_OFFSET);
+}
+
+/*
+ * Transfer the data over the DMA channel
+ */
+void big_sur_ge_dma_transfer(xdma_channel *dma, unsigned long *source,
+				unsigned long *dest, unsigned long length)
+{
+	/* Source Address */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_SA_REG_OFFSET, 
+				(unsigned long)source);
+
+	/* Destination Address */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DA_REG_OFFSET,
+				(unsigned long)dest);
+
+	/* Length of the data */
+	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_LEN_REG_OFFSET,
+				length);
+}
+
+/*
+ * Init the packet fifo only in the FIFO mode
+ */
+int packet_fifo_init(packet_fifo *fifo, u32 reg, u32 data)
+{
+	fifo->reg_base_addr = reg;
+	fifo->data_base_address = data;
+	fifo->ready_status = 1;
+
+	BIG_SUR_GE_FIFO_RESET(fifo);
+
+	return 0;
+}
+
+/*
+ * Write to the packet FIFO, 32-bit at a time. 
+ */
+static int packet_fifo_write(packet_fifo * fifo, int *buffer, int len)
+{
+	unsigned long fifo_count, word_count, extra_byte;
+	unsigned long *buffer_data = (unsigned long *) buffer;
+
+	fifo_count =
+	    BIG_SUR_GE_READ(fifo->reg_base_addr +
+			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
+	fifo_count &= BIG_SUR_GE_COUNT_MASK;
+
+	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+
+	if (extra_byte > 0)
+		if (fifo_count > (word_count + 1)) {
+			printk(KERN_ERR
+			       "No room in the packet send fifo \n");
+			return -1;
+		}
+
+	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
+		BIG_SUR_GE_WRITE(fifo->data_base_address,
+				 buffer_data[fifo_count]);
+
+	if (extra_byte > 0) {
+		unsigned long last_word = 0;
+		int *extra_buffer_data =
+		    (int *) (buffer_data + word_count);
+
+		if (extra_byte == 1)
+			last_word = extra_buffer_data[0] << 24;
+		else if (extra_byte == 2)
+			last_word = (extra_buffer_data[0] << 24 |
+				     extra_buffer_data[1] << 16);
+
+		else if (extra_byte == 3)
+			last_word = (extra_buffer_data[0] << 24 |
+				     extra_buffer_data[1] << 16 |
+				     extra_buffer_data[2] << 8);
+
+
+		BIG_SUR_GE_WRITE(fifo->data_base_address, last_word);
+	}
+
+	return 0;
+}
+
+/*
+ * Start transmitting the packet 
+ */
+int big_sur_tx(big_sur_ge *emac, u8 *buffer, unsigned long byte_cnt)
+{
+	unsigned long int_status, reg_data, status_reg;
+
+	if ( (!emac->started) && (emac->polled) &&
+		(emac->dma_sg) ) 
+		return -1;
+
+	/* There is space in the FIFO */
+	int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
+	if (int_status & BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK) {
+		printk(KERN_ERR "Tx FIFO error: Queue is Full \n");
+		return -1;
+	}
+
+	/*
+	 * Check if there is enough space for this packet
+	 */
+	if ((BIG_SUR_GE_GET_COUNT(&emac->send_fifo) * sizeof(unsigned long)) < byte_cnt) {
+		printk(KERN_ERR "Send FIFO on chip is full \n");
+		return -1;
+	}
+
+	if (emac->has_dma == 0) {
+		/* Write to the Send FIFO */
+		if (packet_fifo_write(&emac->send_fifo, buffer, byte_cnt) == -1) {
+			printk(KERN_ERR "Error : Could not write to FIFO \n");
+			return -1;
+		}
+
+		/* Write the MSB of the length */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FF4, (byte_cnt & 0xff00));
+
+		/* Write the LSB of the length */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FF8, (byte_cnt & 0x00ff));
+
+		/* Write the Status bit */
+		BIG_SUR_GE_WRITE(emac->base_address + 0x1FFC, 0x80000000);
+	
+		/* Make sure MAC has done transmitting */	
+		status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
+		while (!(status_reg & 0x80000000)) {
+			status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
+			if (!(status_reg & 0x80000000))
+				break;
+		}
+
+	}
+	else {
+		/* DMA Engine is not buzy */
+		if (big_sur_ge_dma_status(&emac->send_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			printk(KERN_ERR "Send channel FIFO engine busy \n");
+			return -1;
+		}
+
+		/* Get ready to transfer the data */
+		big_sur_ge_set_dma_control(&emac->send_channel, 
+					BIG_SUR_GE_DMACR_SOURCE_INCR_MASK |
+					BIG_SUR_GE_DMACR_DEST_LOCAL_MASK  |
+					BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
+
+		big_sur_ge_dma_transfer(&emac->send_channel, (unsigned long *)buffer, 
+					(unsigned long *)(emac->base_address + 
+					BIG_SUR_GE_PFIFO_TXDATA_OFFSET), byte_cnt);
+
+		/* Check the DMA Engine status */	
+		reg_data = big_sur_ge_dma_status(&emac->send_channel);
+		while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
+                	reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+	                if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
+        	                break;
+        	}
+
+		/* Check for any DMA errors */
+		if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) || 
+			(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
+				printk(KERN_ERR "Send side DMA error \n");
+				return -1;
+		}
+
+		/* Write the packet length */
+		BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_TPLR_OFFSET, byte_cnt);
+	}
+
+	/* Good Send */
+	return 0;
+}
+
+/*
+ * Read the packet FIFO
+ */
+static int packet_fifo_read(packet_fifo * fifo, u8 * buffer, unsigned int len)
+{
+	unsigned long fifo_count, word_count, extra_byte;
+	unsigned long *buffer_data = (unsigned long *) buffer;
+
+	fifo_count =
+	    BIG_SUR_GE_READ(fifo->reg_base_addr +
+			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
+	fifo_count &= BIG_SUR_GE_COUNT_MASK;
+
+	if ((fifo_count * BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT) < len)
+		return -1;
+
+	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
+
+	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
+		buffer_data[fifo_count] =
+		    BIG_SUR_GE_READ(fifo->reg_base_addr);
+
+	if (extra_byte > 0) {
+		unsigned long last_word;
+		int *extra_buffer_data =
+		    (int *) (buffer_data + word_count);
+
+		last_word = BIG_SUR_GE_READ(fifo->data_base_address);
+		if (extra_byte == 1)
+			extra_buffer_data[0] = (int) (last_word << 24);
+		else if (extra_byte == 2) {
+			extra_buffer_data[0] = (int) (last_word << 24);
+			extra_buffer_data[1] = (int) (last_word << 16);
+		} else if (extra_byte == 3) {
+			extra_buffer_data[0] = (int) (last_word << 24);
+			extra_buffer_data[1] = (int) (last_word << 16);
+			extra_buffer_data[2] = (int) (last_word << 8);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * FIFO receive for Simple DMA case
+ */
+int big_sur_rx(big_sur_ge *emac, u8 *buffer, unsigned long *byte_cnt)
+{
+	unsigned long int_status, reg_data, packet_length;
+
+        if ( (!emac->started) && (emac->polled) &&
+		(emac->dma_sg) ) {
+                return -1;
+	}
+
+	/* Not enough space in the current buffer */	
+	if (*byte_cnt < BIG_SUR_GE_MAX_FRAME_SIZE)
+		return -1;
+
+	int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
+
+	/* FIFO is empty */
+	if (int_status & BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK) {
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET, 
+					BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK);
+		return -1;
+	}
+
+	packet_length = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_RPLR_OFFSET);
+
+	if (emac->has_dma == 0) {
+		reg_data = BIG_SUR_GE_READ(emac->base_address + 0x3FFC);
+		if (reg_data & 0x80000000) {
+			if (packet_fifo_read(&emac->recv_fifo, buffer, packet_length) == -1) {
+				printk(KERN_ERR "Could not read the packet fifo \n");
+				return -1;
+			}
+
+			BIG_SUR_GE_WRITE(emac->base_address + 0x3FFC, 0x0);
+		}
+	}
+	else {	
+		/* Rx side DMA engine */
+		if (big_sur_ge_dma_status(&emac->recv_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			printk(KERN_ERR "Rx side DMA Engine busy \n");
+			return -1;
+		}
+
+		if (packet_length == 0) {
+			printk(KERN_ERR "MAC has the FIFO packet length 0 \n");
+			return -1;
+		}
+
+		/* For the simple DMA case only */
+		big_sur_ge_set_dma_control(&emac->recv_channel, 
+							BIG_SUR_GE_DMACR_DEST_INCR_MASK |
+							BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK |
+							BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
+
+		big_sur_ge_dma_transfer(&emac->recv_channel, (unsigned long *)
+					(emac->base_address + 
+					BIG_SUR_GE_PFIFO_RXDATA_OFFSET), (unsigned long *)
+					buffer, packet_length);
+
+		reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+		while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
+			reg_data = big_sur_ge_dma_status(&emac->recv_channel);
+			if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
+					break;
+		}	
+
+		if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) || 
+			(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
+				printk(KERN_ERR "DMA Bus Error \n");
+				return -1;
+		}
+	}
+
+	*byte_cnt = packet_length;
+	
+	return 0;
+}
+
+/*
+ * Main FIFO Interrupt Handler
+ */
+void big_sur_ge_fifo_intr(unsigned long data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	big_sur_ge *emac = (big_sur_ge *)lp->emac;
+
+	/* Read the interrupt status */
+	unsigned long int_status = BIG_SUR_GE_READ(emac->base_address +
+							XIIF_V123B_DIPR_OFFSET);
+
+	/* Handle Rx and Tx */
+	if (int_status & BIG_SUR_GE_IPIF_EMAC_MASK)
+		handle_intr(netdev, emac);
+
+	/* Handle Receive Error */
+	if (int_status & BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
+		big_sur_ge_check_fifo_recv_error(netdev, emac);
+
+	/* Handle Transmit Error */
+	if (int_status & BIG_SUR_GE_IPIF_SEND_FIFO_MASK)
+		big_sur_ge_check_fifo_send_error(netdev, emac);
+
+	/* Clear the errors */
+	if (int_status & XIIF_V123B_ERROR_MASK)
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DISR_OFFSET, 
+							XIIF_V123B_ERROR_MASK);
+}
+
+/*
+ * Tasklet function to invoke interrupt
+ */
+void big_sur_tasklet_schedule(void *data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+
+	tasklet_schedule(&lp->big_sur_tasklet);
+	
+	return;
+}
+
+/*
+ * Main intr handler 
+ */
+static void handle_intr(struct net_device *netdev, big_sur_ge *emac)
+{
+	unsigned long int_status = BIG_SUR_GE_READ(emac->base_address + 
+						XIIF_V123B_IISR_OFFSET);
+
+	/* Process the Rx side */
+	if (int_status & BIG_SUR_GE_EIR_RECV_DONE_MASK) {
+		big_sur_receive(netdev);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET, 
+						BIG_SUR_GE_EIR_RECV_DONE_MASK);
+	}
+
+	/* Process the Tx side */
+	if (int_status & BIG_SUR_GE_EIR_XMIT_DONE_MASK) {
+		big_sur_tx_free_skb(netdev);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
+                                                BIG_SUR_GE_EIR_XMIT_DONE_MASK);
+	}
+
+	big_sur_ge_check_mac_error(emac, int_status);
+}
+/*
+ * For now, the MAC address errors dont trigger a update of the 
+ * stats. There is no stats framework in place. Hence, we just
+ * check for the errors below and do a reset if needed. 
+ */
+void big_sur_ge_check_mac_error(big_sur_ge *emac, unsigned long int_status)
+{
+	if (int_status & (BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK | 
+				BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |
+				BIG_SUR_GE_EIR_RECV_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |
+				BIG_SUR_GE_EIR_RECV_COLLISION_MASK |
+				BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |
+				BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK |
+				BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK |
+				BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK |
+				BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK) ) {
+
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET, 0);
+		big_sur_ge_enet_reset(emac);
+	}
+}
+
+/*
+ * Check for FIFO Recv errors
+ */
+void big_sur_ge_check_fifo_recv_error(struct net_device *netdev, big_sur_ge *emac)
+{
+	if (BIG_SUR_GE_IS_DEADLOCKED(&emac->recv_fifo)) {
+		unsigned long intr_enable;
+
+		/*
+		 * The only way to ack this interrupt is to reset the 
+		 * device. However, before we reset, we make sure this
+		 * interrupt is disabled
+		 */
+		intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable & ~(BIG_SUR_GE_IPIF_RECV_FIFO_MASK)));
+
+		/* Reset the device */
+		big_sur_ge_reset(netdev, UNKNOWN);
+
+		/* Turn the interrupts back on */
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable | BIG_SUR_GE_IPIF_RECV_FIFO_MASK));
+
+	}
+}
+
+/*
+ * Check for FIFO Send errors
+ */
+void big_sur_ge_check_fifo_send_error(struct net_device *netdev, big_sur_ge *emac)
+{
+        if (BIG_SUR_GE_IS_DEADLOCKED(&emac->send_fifo)) {
+		unsigned long intr_enable;
+
+		/* Disable the interrupt first */
+		intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+                                        (intr_enable & ~(BIG_SUR_GE_IPIF_SEND_FIFO_MASK)));
+
+		/* Reset the device */
+		big_sur_ge_reset(netdev, UNKNOWN);
+
+		/* Turn the interrupts back on */
+		BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
+					(intr_enable | BIG_SUR_GE_IPIF_SEND_FIFO_MASK));
+	}
+}
+
+/*
+ * GE unit init
+ */
+int big_sur_ge_enet_init(big_sur_ge *emac, unsigned int device_id)
+{
+	big_sur_ge_config *config;
+	int err;
+	
+	/* Assume that the device has been stopped */
+	config = big_sur_ge_get_config(device_id);
+	if (config == NULL)
+		return -1;
+
+	emac->ready = 0;
+	emac->started = 0;
+	emac->dma_sg = 0; 
+	emac->has_mii = config->has_mii;
+	emac->has_mcast_hash_table = 0;
+	emac->dma_config = config->dma_config;
+	emac->base_address = config->base_address;
+
+	if (big_sur_ge_config_dma(emac) == -1)
+		return -1;
+
+	if (emac->has_dma == 0) {
+		err = big_sur_ge_config_fifo(emac);
+		if (err == -1)
+			return err;
+	}
+
+	/* Now, we know that the FIFO initialized successfully. So, set the ready flag */
+	emac->ready = 1;
+
+	/* Do we need a PHY reset here also. It did cause problems on some boards */	
+	big_sur_ge_enet_reset(emac);
+
+	/* PHY reset code. Remove if causes a problem on the board */
+	big_sur_ge_reset_phy(emac->base_address);
+
+	return 0;
+}
+
+/*
+ * Start the GE unit for Tx, Rx and Interrupts
+ */
+int big_sur_ge_start(big_sur_ge *emac)
+{
+	unsigned long		reg_data;
+	
+	/*
+	 * Basic mode of operation is polled and interrupt mode. 
+	 * We disable the polled mode for good. We may use the 
+	 * polled mode for Rx NAPI but that does not require all 
+	 * the interrupts to be disabled
+	 */
+	emac->polled = 0;
+
+	/*
+ 	 * DMA: Three modes of operation - simple, FIFO, SG. 
+	 * SG is surely not working and so is kept off using the 
+	 * dma_sg flag. Simple and FIFO work. But, we may not use FIFO 
+	 * at all. So, we enable the interrupts below
+	 */
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET, 
+				BIG_SUR_GE_IPIF_FIFO_DFT_MASK | XIIF_V123B_ERROR_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET,
+				BIG_SUR_GE_EIR_DFT_FIFO_MASK);
+
+	/* Toggle the started flag */
+	emac->started = 1;
+
+	/* Start the Tx and Rx units respectively */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | BIG_SUR_GE_ECR_RECV_RESET_MASK);
+	reg_data |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
+	
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+	return 0;
+}
+
+/*
+ * Stop the GE unit
+ */
+int big_sur_ge_stop(big_sur_ge *emac)
+{
+	unsigned long	reg_data;
+
+	/* We assume that the device is not already stopped */
+	if (!emac->started)
+		return 0;
+
+	/* Disable the Tx and Rx unit respectively */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+	/* Disable the interrupts */
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DGIER_OFFSET, 0);
+
+	/* Toggle the started flag */
+	emac->started = 0;
+
+	return 0;
+}
+
+/*
+ * Reset the GE MAC unit 
+ */
+void big_sur_ge_enet_reset(big_sur_ge *emac)
+{
+	unsigned long reg_data;
+
+	(void) big_sur_ge_stop(emac);
+
+	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_RESETR_OFFSET, 
+			XIIF_V123B_RESET_MASK);
+	
+	/*
+         * For now, configure the receiver to not strip off 
+	 * FCS and padding since this is not currently supported. 
+	 * In the future, just take the default and provide the option 
+	 * for the user to change this behavior.
+         */
+	reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+	reg_data &= ~(BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK);
+	reg_data &= ~(BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+}
+
+/*
+ * Set the MAC address of the GE mac unit 
+ */
+int big_sur_ge_set_mac_address(big_sur_ge *emac, unsigned char *addr)
+{
+	unsigned long	mac_addr = 0;
+
+	/* Device is started and so mac address must be set */
+	if (emac->started == 1)
+		return 0;
+
+	/* Address High */
+	mac_addr = ( (addr[0] << 8) | addr[1]);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAH_OFFSET, mac_addr);
+
+	/* Address Low */
+	mac_addr |= ( (addr[2] << 24) | (addr[3] << 16) | 
+			(addr[4] << 8) | addr[5]);
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAL_OFFSET, mac_addr);
+	
+	return 0;
+}
+
+/*
+ * Get the MAC address of the GE MAC unit
+ */
+void big_sur_ge_get_mac_unit(big_sur_ge *emac, unsigned int *addr)
+{
+	unsigned long	mac_addr_hi, mac_addr_lo;
+
+	mac_addr_hi = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAH_OFFSET);
+	mac_addr_lo = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAL_OFFSET);
+
+	addr[0] = (mac_addr_hi >> 8);
+	addr[1] = mac_addr_hi;
+
+	addr[2] = (mac_addr_lo >> 24);
+	addr[3] = (mac_addr_lo >> 16);
+	addr[4] = (mac_addr_lo >> 8);
+	addr[5] = mac_addr_lo;
+}
+
+/*
+ * Configure the GE MAC for DMA capabilities, only Simple
+ */
+static int big_sur_ge_config_dma(big_sur_ge *emac)
+{
+	/* Supports Simple DMA */
+	emac->has_dma = 1;
+
+	if (big_sur_ge_dma_init(&emac->recv_channel, emac->base_address +
+				BIG_SUR_GE_DMA_RECV_OFFSET) == -1) {
+		printk(KERN_ERR "Could not initialize the DMA unit  \n");
+		return -1;
+	}
+
+	if (big_sur_ge_dma_init(&emac->send_channel, emac->base_address +
+                                BIG_SUR_GE_DMA_SEND_OFFSET) == -1) {
+		printk(KERN_ERR "Could not initialize the DMA unit  \n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the FIFO for simple DMA
+ */
+static int big_sur_ge_config_fifo(big_sur_ge *emac)
+{
+	int err = 0;
+
+	/* Receive side packet FIFO */
+	err = packet_fifo_init(&emac->recv_fifo, emac->base_address + 
+				BIG_SUR_GE_PFIFO_RXREG_OFFSET, emac->base_address +
+				BIG_SUR_GE_PFIFO_RXDATA_OFFSET);
+
+	if (err == -1) {
+		printk(KERN_ERR "Could not initialize Rx packet FIFO for Simple DMA \n");
+		return err;
+	}
+
+	/* Send side Packet FIFO */
+	err = packet_fifo_init(&emac->send_fifo, emac->base_address +
+				BIG_SUR_GE_PFIFO_TXREG_OFFSET, emac->base_address +
+				BIG_SUR_GE_PFIFO_TXDATA_OFFSET);
+
+	if (err == -1) {
+		printk(KERN_ERR "Could not initialize Tx packet FIFO for Simple DMA \n");
+	}
+
+	return err;
+}
+
+typedef struct {
+        unsigned long   option;
+        unsigned long   mask;
+} option_map;
+
+static option_map option_table[] = {
+        {BIG_SUR_GE_UNICAST_OPTION, BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK},
+        {BIG_SUR_GE_BROADCAST_OPTION, BIG_SUR_GE_ECR_BROAD_ENABLE_MASK},
+        {BIG_SUR_GE_PROMISC_OPTION, BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK},
+        {BIG_SUR_GE_FDUPLEX_OPTION, BIG_SUR_GE_ECR_FULL_DUPLEX_MASK},
+        {BIG_SUR_GE_LOOPBACK_OPTION, BIG_SUR_GE_ECR_LOOPBACK_MASK},
+        {BIG_SUR_GE_MULTICAST_OPTION, BIG_SUR_GE_ECR_MULTI_ENABLE_MASK},
+        {BIG_SUR_GE_FLOW_CONTROL_OPTION, BIG_SUR_GE_ECR_PAUSE_FRAME_MASK},
+        {BIG_SUR_GE_INSERT_PAD_OPTION, BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK},
+        {BIG_SUR_GE_INSERT_FCS_OPTION, BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK},
+        {BIG_SUR_GE_INSERT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK},
+        {BIG_SUR_GE_OVWRT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK},
+        {BIG_SUR_GE_STRIP_PAD_OPTION, BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK},
+        {BIG_SUR_GE_STRIP_FCS_OPTION, BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK},
+        {BIG_SUR_GE_STRIP_PAD_FCS_OPTION, BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK}
+};
+
+#define BIG_SUR_GE_NUM_OPTIONS          (sizeof(option_table) / sizeof(option_map))
+
+/*
+ * Set the options for the GE
+ */
+int big_sur_ge_set_options(big_sur_ge *emac, unsigned long option_flag)
+{
+        unsigned long reg_data;
+        unsigned int index;
+
+        /* Assume that the device is stopped before calling this function */
+
+        reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+        for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
+                if (option_flag & option_table[index].option)
+                        reg_data |= option_table[index].mask;
+                else
+                        reg_data &= ~(option_table[index].mask);
+
+        }
+
+        BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
+
+        /* No polled option */
+        emac->polled = 0;
+        return 0;
+}
+
+/*
+ * Get the options from the GE
+ */
+unsigned long big_sur_ge_get_options(big_sur_ge *emac)
+{
+        unsigned long option_flag = 0, reg_data;
+        unsigned int index;
+
+        reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
+
+        for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
+                if (option_flag & option_table[index].option)
+                        reg_data |= option_table[index].mask;
+        }
+
+        return option_flag;
+}
+
+/*
+ * Set the Inter frame gap
+ */
+int big_sur_ge_set_frame_gap(big_sur_ge *emac, int part1, int part2)
+{
+        unsigned long config;
+
+        /* Assume that the device is stopped before calling this */
+
+        config = ( (part1 << BIG_SUR_GE_IFGP_PART1_SHIFT) |
+                        (part2 << BIG_SUR_GE_IFGP_PART2_SHIFT) );
+
+        BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_IFGP_OFFSET, config);
+
+        return 0;
+}
+
+/*
+ * Get the Inter frame gap
+ */
+void big_sur_ge_get_frame_gap(big_sur_ge *emac, int *part1, int *part2)
+{
+        unsigned long config;
+
+        config = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_IFGP_OFFSET);
+        *part1 = ((config & BIG_SUR_GE_IFGP_PART1_SHIFT) >> BIG_SUR_GE_IFGP_PART1_SHIFT);
+        *part2 = ((config & BIG_SUR_GE_IFGP_PART2_SHIFT) >> BIG_SUR_GE_IFGP_PART2_SHIFT);
+}
+
+/*
+ * PHY specific functions for the MAC
+ */
+#define	BIG_SUR_GE_MAX_PHY_ADDR		32
+#define	BIG_SUR_GE_MAX_PHY_REG		32
+
+/*
+ * Read the PHY reg
+ */
+int big_sur_ge_phy_read(big_sur_ge *emac, unsigned long addr, 
+				unsigned long reg_num, unsigned int *data)
+{
+	unsigned long mii_control, mii_data;
+
+	if (!emac->has_mii)
+		return -1;
+
+	mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
+	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
+		printk(KERN_ERR "PHY busy \n");
+		return -1;
+	}
+
+	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
+	mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
+	mii_control |= (BIG_SUR_GE_MGTCR_RW_NOT_MASK | BIG_SUR_GE_MGTCR_START_MASK |
+				BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
+
+	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK) 
+		if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
+			break;
+
+	mii_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET);
+	*data = (unsigned int) mii_data;
+
+	return 0;
+}
+
+/*
+ * Write to the PHY register
+ */
+int big_sur_ge_phy_write(big_sur_ge *emac, unsigned long addr,
+				unsigned long reg_num, unsigned int data)
+{
+	unsigned long		mii_control;
+
+	if (!emac->has_mii)
+                return -1;
+
+	mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
+	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
+                printk(KERN_ERR "PHY busy \n");
+                return -1;
+        }
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET, (unsigned long)data);
+	
+	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
+        mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
+        mii_control |= (BIG_SUR_GE_MGTCR_START_MASK | BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
+
+	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
+
+	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
+                if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
+                        break;
+
+	return 0;
+}
+
+/*
+ * Reset the GE system
+ */
+static void big_sur_ge_reset(struct net_device *netdev, DUPLEX duplex)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	struct sk_buff *skb;
+	unsigned long options;
+	int ifcfg1, ifcfg2;
+
+	/* Stop the queue */
+	netif_stop_queue(netdev);
+
+	big_sur_ge_get_frame_gap(lp->emac, &ifcfg1, &ifcfg2);
+	options = big_sur_ge_get_options(lp->emac);
+	switch (duplex) {
+		case HALF_DUPLEX:
+			options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
+			break;
+
+		case FULL_DUPLEX:
+			options |= BIG_SUR_GE_FDUPLEX_OPTION;
+			break;
+
+		case UNKNOWN:
+			break;
+	}
+
+	big_sur_ge_enet_reset(lp->emac);
+
+	/* Set the necessary options for the MAC unit */
+	big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr);
+	big_sur_ge_set_frame_gap(lp->emac, ifcfg1, ifcfg2);
+	big_sur_ge_set_options(lp->emac, options);
+
+	(void) big_sur_ge_start(lp->emac);
+
+	spin_lock_irq(lp->lock);
+	skb = lp->saved_skb;
+	lp->saved_skb = NULL;
+	spin_unlock_irq(lp->lock);
+
+	if (skb) 
+		dev_kfree_skb(skb);
+
+	/* Start the queue, in case it was stopped */
+	netif_wake_queue(netdev);
+}
+
+/*
+ * Get the PHY status and then configure the 
+ * speed, duplex, link status etc.
+ */
+static int big_sur_ge_get_phy_status(struct net_device *netdev, 
+					DUPLEX *duplex, int *linkup)
+{
+	struct big_sur_ge_enet  *lp = netdev->priv;
+	unsigned int		reg_data;
+	int			err = 0;
+
+	err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMCR, &reg_data);
+	if (err == -1) {
+		printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+		return err;
+	}
+
+	if (!(reg_data & BMCR_ANENABLE)) {
+		if (reg_data & BMCR_FULLDPLX) 
+			*duplex = FULL_DUPLEX;
+		else
+			*duplex = HALF_DUPLEX;
+	}
+	else {
+		unsigned int advertise, partner, neg;
+	
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_ADVERTISE, &advertise);
+		if (err == -1) {
+	                printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+        	        return err;
+		}
+
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_LPA, &partner);
+		if (err == -1) {
+                        printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+                        return err;
+                }
+
+		neg = advertise & partner & ADVERTISE_ALL;
+		if (neg & ADVERTISE_100FULL)
+                        *duplex = FULL_DUPLEX;
+                else if (neg & ADVERTISE_100HALF)
+                        *duplex = HALF_DUPLEX;
+                else if (neg & ADVERTISE_10FULL)
+                        *duplex = FULL_DUPLEX;
+                else
+                        *duplex = HALF_DUPLEX;
+
+		err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMSR, &reg_data);
+		if (err == -1) {
+                        printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
+                        return err;
+                }
+
+		*linkup = (reg_data & BMSR_LSTATUS) != 0;
+
+	}
+	return 0;
+}
+
+/*
+ * Poll the MII for duplex and link status 
+ */
+static void big_sur_ge_poll_mii(unsigned long data)
+{
+	struct net_device *netdev = (struct net_device *) data;	
+	struct big_sur_ge_enet* lp = netdev->priv;
+	unsigned long options;
+	DUPLEX mac_duplex, phy_duplex;
+	int phy_carrier, netif_carrier;
+
+	if (big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier) == -1) {
+		printk(KERN_ERR "%s: Terminating link monitoring.\n", netdev->name);
+		return;
+	}
+
+	options = big_sur_ge_get_options(lp->emac);
+	if (options & BIG_SUR_GE_FDUPLEX_OPTION)
+		mac_duplex = FULL_DUPLEX;
+	else
+		mac_duplex = HALF_DUPLEX;
+
+	if (mac_duplex != phy_duplex) {
+		tasklet_disable(&lp->big_sur_tasklet);
+		big_sur_ge_reset(netdev, phy_duplex);
+		tasklet_enable(&lp->big_sur_tasklet);
+	}
+
+	netif_carrier = netif_carrier_ok(netdev) != 0;
+
+        if (phy_carrier != netif_carrier) {
+                if (phy_carrier) {
+                        printk(KERN_INFO "%s: Link carrier restored.\n",
+                               netdev->name);
+                        netif_carrier_on(netdev);
+                } else {
+                        printk(KERN_INFO "%s: Link carrier lost.\n", netdev->name);
+                        netif_carrier_off(netdev);
+                }
+        }
+
+        /* Set up the timer so we'll get called again in 2 seconds. */
+        lp->phy_timer.expires = jiffies + 2 * HZ;
+        add_timer(&lp->phy_timer);
+}
+
+/*
+ * Open the network interface
+ */
+static int big_sur_ge_open(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	unsigned long options;
+	DUPLEX phy_duplex, mac_duplex;
+	int phy_carrier;
+
+	(void) big_sur_ge_stop(lp->emac);
+
+	if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
+		printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
+		return -EIO;
+	}
+
+	options = big_sur_ge_get_options(lp->emac);
+
+	/*
+	 * This MAC unit has no support for Interrupts. So, we initialize
+	 * a tasklet here that will be scheduled from the timer
+	 * interrupt handler. Note that we cannot run the receive
+	 * and the transmit functions as part of an interrupt handler. Since,
+	 * this will be disastrous for the timer under load. Hence, tasklet
+	 * is the best way to go
+	 */
+	tasklet_init(&lp->big_sur_tasklet, big_sur_ge_fifo_intr, (unsigned long)netdev);
+
+	if (!(big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier))) {
+		if (options & BIG_SUR_GE_FDUPLEX_OPTION)
+			mac_duplex = FULL_DUPLEX;
+		else
+			mac_duplex = HALF_DUPLEX;
+
+		if (mac_duplex != phy_duplex) {
+			switch (phy_duplex) {
+				case HALF_DUPLEX: 
+					options &= ~(BIG_SUR_GE_FDUPLEX_OPTION); 
+					break;
+				case FULL_DUPLEX:
+					options |= BIG_SUR_GE_FDUPLEX_OPTION;
+					break;
+				case UNKNOWN:
+					break;
+			}
+
+			big_sur_ge_set_options(lp->emac, options);
+		}
+	}
+
+	if (big_sur_ge_start(lp->emac) == -1) {
+		printk(KERN_ERR "%s: Could not start device.\n", netdev->name);
+		tasklet_kill(&lp->big_sur_tasklet);
+		return -EBUSY;
+	}
+
+	MOD_INC_USE_COUNT;
+	netif_start_queue(netdev);
+
+	lp->phy_timer.expires = jiffies + 2*HZ;
+        lp->phy_timer.data = (unsigned long)netdev;
+        lp->phy_timer.function = &big_sur_ge_poll_mii;
+	add_timer(&lp->phy_timer);
+
+	return 0;
+}
+
+/*
+ * Close the network device interface
+ */
+static int big_sur_ge_close(struct net_device *netdev)
+{
+	struct big_sur_ge_enet  *lp = netdev->priv;
+	
+	del_timer_sync(&lp->phy_timer);
+	netif_stop_queue(netdev);
+
+	if (big_sur_ge_stop(lp->emac) == -1) {
+		printk(KERN_ERR "%s: Could not stop device.\n", netdev->name);
+		return -EBUSY;
+        }
+
+	tasklet_kill(&lp->big_sur_tasklet);
+
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+/*	
+ * Get the network device stats. 
+ */
+static struct net_device_stats *big_sur_ge_get_stats(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	
+	return lp->stats;
+}
+
+/*
+ * FIFO send for a packet that needs to be transmitted
+ */
+static int big_sur_start_xmit(struct sk_buff *orig_skb, struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct sk_buff *new_skb;
+	unsigned int len, align;
+	struct net_device_stats *stats = lp->stats;
+
+	/* 
+	 * The FIFO takes a single request at a time. Stop the queue to
+	 * accomplish this.  We'll wake the queue in the transmit
+	 * routine below or in the timeout routine
+	 */
+	netif_stop_queue(netdev);
+        len = orig_skb->len;
+
+	/*
+	 * Align the packet for the FIFO
+	 */
+	if (!(new_skb = dev_alloc_skb(len + 4))) {
+                dev_kfree_skb(orig_skb);
+                printk(KERN_ERR "%s: Could not allocate transmit buffer.\n",
+                       netdev->name);
+                netif_wake_queue(netdev);
+                return -EBUSY;
+        }
+
+	align = 4 - ((unsigned long) new_skb->data & 3);
+        if (align != 4)
+                skb_reserve(new_skb, align);
+
+	skb_put(new_skb, len);
+        memcpy(new_skb->data, orig_skb->data, len);
+
+	dev_kfree_skb(orig_skb);
+	lp->saved_skb = new_skb;
+
+	/* Do the actual transmit */
+	if (big_sur_tx(lp->emac, (u8 *) new_skb->data, len) == -1) {
+		spin_lock_irq(&lp->lock);
+                new_skb = lp->saved_skb;
+                lp->saved_skb = NULL;
+                spin_unlock_irq(&lp->lock);
+
+                dev_kfree_skb(new_skb);
+                printk(KERN_ERR "%s: Could not transmit buffer.\n", netdev->name);
+                netif_wake_queue(netdev);
+                return -EIO;
+        }
+
+	stats->tx_bytes += len;
+	stats->tx_packets++;
+
+        return 0;
+}
+
+/*
+ * Free the skb
+ */
+static void big_sur_tx_free_skb(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct sk_buff *skb;
+
+	spin_lock_irq(&lp->lock);
+	skb = lp->saved_skb;
+        lp->saved_skb = NULL;
+        spin_unlock_irq(&lp->lock);
+	
+	if (skb)
+		dev_kfree_skb(skb);
+
+	/* Start the queue since we know that packet has been transmitted */
+        netif_wake_queue(netdev);
+}
+
+/*
+ * Handle the timeout of the ethernet device 
+ */
+static void big_sur_ge_tx_timeout(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev;
+
+	printk("%s: Exceeded transmit timeout of %lu ms.  Resetting mac.\n",
+			netdev->name, TX_TIMEOUT * 1000UL / HZ);
+
+	tasklet_disable(&lp->big_sur_tasklet);
+	big_sur_ge_reset(netdev, UNKNOWN);
+	tasklet_enable(&lp->big_sur_tasklet);
+}
+
+/*
+ * Receive the packets
+ */
+static void big_sur_receive(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	struct sk_buff *skb;
+	unsigned long len = BIG_SUR_GE_MAX_FRAME_SIZE;
+	unsigned int align;
+	struct net_device_stats *stats = lp->stats;
+	
+	if (!(skb = dev_alloc_skb(len + 4))) {
+		printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
+			netdev->name);
+		return;
+	}
+
+	align = 4 - ((unsigned long) skb->data & 3);
+        if (align != 4)
+                skb_reserve(skb, align);
+
+	if (big_sur_rx(lp->emac, (u8 *)skb->data, &len) == -1) {
+		dev_kfree_skb(skb);
+		
+		printk(KERN_ERR "%s: Could not receive buffer \n", netdev->name);
+		netdev->tx_timeout = NULL;
+		big_sur_ge_reset(netdev, UNKNOWN);
+		netdev->tx_timeout = big_sur_ge_tx_timeout;
+	}
+
+	skb_put(skb, len);
+        skb->dev = netdev;
+        skb->protocol = eth_type_trans(skb, netdev);
+
+	stats->rx_packets++;
+	stats->rx_bytes += len;
+
+	/* Good Rx, send the packet upstream. */
+	netif_rx(skb);
+}
+
+/*
+ * Set the Multicast Hash list
+ */
+static void big_sur_ge_set_multi(struct net_device *netdev)
+{
+	struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
+	unsigned long options;
+
+	tasklet_disable(&lp->big_sur_tasklet);
+
+	(void) big_sur_ge_stop(lp->emac);
+	options = big_sur_ge_get_options(lp->emac);
+	options &= ~(BIG_SUR_GE_PROMISC_OPTION | BIG_SUR_GE_MULTICAST_OPTION);
+
+	if (netdev->flags & IFF_PROMISC) 
+		options |= BIG_SUR_GE_PROMISC_OPTION;
+	
+	(void) big_sur_ge_start(lp->emac);
+
+	tasklet_enable(&lp->big_sur_tasklet);
+}	
+
+/*
+ * IOCTL support
+ */
+static int big_sur_ge_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	struct big_sur_ge_enet *lp = netdev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
+
+	switch(cmd) {
+		case SIOCGMIIPHY:       	/* Get address of MII PHY in use. */
+	        case SIOCDEVPRIVATE:    	/* for binary compat, remove in 2.5 */
+                	data->phy_id = lp->mii_addr;
+
+        	case SIOCGMIIREG:   	    	/* Read MII PHY register. */
+	        case SIOCDEVPRIVATE + 1: 	/* for binary compat, remove in 2.5 */
+                	if (data->phy_id > 31 || data->reg_num > 31)
+                        	return -ENXIO;
+
+                	del_timer_sync(&lp->phy_timer);
+
+			if (big_sur_ge_phy_read(lp->emac, data->phy_id, 
+						data->reg_num, &data->val_out) == -1) {
+				printk(KERN_ERR "%s: Could not read from PHY", netdev->name);
+				return -EBUSY;
+			}
+
+			lp->phy_timer.expires = jiffies + 2*HZ;
+	                add_timer(&lp->phy_timer);
+				
+			return 0;
+
+		case SIOCSMIIREG:       	/* Write MII PHY register. */
+	        case SIOCDEVPRIVATE + 2:        /* for binary compat, remove in 2.5 */
+			if (data->phy_id > 31 || data->reg_num > 31)
+				return -ENXIO;
+	
+			del_timer_sync(&lp->phy_timer);
+
+			if (big_sur_ge_phy_write(lp->emac, data->phy_id, data->reg_num,
+							data->val_in) == -1) {
+				printk(KERN_ERR "%s: Could not write to PHY", netdev->name);
+				return -EBUSY;
+			}
+
+			lp->phy_timer.expires = jiffies + 2*HZ;
+			add_timer(&lp->phy_timer);
+
+			return 0;
+
+		default:
+			return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * Get the config from the config table 
+ */
+big_sur_ge_config *big_sur_ge_get_config(int index)
+{	
+	/* For port 0 only */
+	big_sur_ge_config *config;
+
+	config->device_id = 0;
+	config->base_address = BIG_SUR_GE_BASE; /* Base Address of the MAC */
+	config->has_counters = 0;
+	config->has_sg_dma = 0;
+	config->dma_config = 0;
+	config->has_mii = 1;
+
+	return (big_sur_ge_config *)config;
+}
+
+/*
+ * Release the network device structure
+ */
+static void big_sur_ge_remove_dev(struct net_device *netdev)
+{
+	struct big_sur_ge_enet  *lp = (struct big_sur_ge_enet *)netdev;
+	big_sur_ge_config	*config;
+
+	config = big_sur_ge_get_config(lp->index);
+	config->base_address = lp->save_base_address;
+	
+	if (lp->saved_skb)
+                dev_kfree_skb(lp->saved_skb);
+        kfree(lp);
+
+        unregister_netdev(netdev);
+        kfree(netdev);
+}
+
+/*
+ * Initial Function to probe the network interface 
+ */
+static int __init big_sur_ge_probe(int index)
+{
+	struct net_device *netdev;
+	struct big_sur_ge_enet *lp;
+	big_sur_ge_config *config;
+	unsigned long maddr;
+
+	config = big_sur_ge_get_config(index);
+	if (!config)
+		return -ENODEV;
+
+	netdev = alloc_etherdev(sizeof(struct big_sur_ge_enet));
+
+	if (!netdev) {
+		printk(KERN_ERR "Could not allocate Big Sur Ethernet device %d.\n",index);
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(netdev);
+
+	lp = (struct big_sur_ge_enet *)netdev->priv;
+	memset(lp, 0, sizeof(struct big_sur_ge_enet));
+	spin_lock_init(&lp->lock);
+	
+	/* Use KSEG1 address */
+	lp->save_base_address = config->base_address;
+	
+	if (big_sur_ge_enet_init(lp->emac, config->device_id) == -1) {
+		printk(KERN_ERR "%s: Could not initialize device.\n", netdev->name);
+		big_sur_ge_remove_dev(netdev);
+		return -ENODEV;
+	}
+
+	memcpy(netdev->dev_addr, big_sur_mac_addr_base, 6);
+	if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
+		printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
+		big_sur_ge_remove_dev(netdev);
+                return -EIO;
+        }
+
+	/* Check the PHY */	
+	lp->mii_addr = 0xff;
+	for (maddr = 0; maddr < 31; maddr++) {
+		unsigned int	reg_data;
+
+		if (big_sur_ge_phy_read(lp->emac, maddr, MII_BMCR, &reg_data) == 0) {
+			lp->mii_addr = maddr;
+                        break;
+                }
+	}
+
+	if (lp->mii_addr == 0xff) {
+                lp->mii_addr = 0;
+                printk(KERN_WARNING
+                       "%s: No PHY detected.  Assuming a PHY at address %d.\n",
+					netdev->name, lp->mii_addr);
+	}
+
+	netdev->open = big_sur_ge_open;
+	netdev->stop = big_sur_ge_close;
+	netdev->get_stats = big_sur_ge_get_stats; 
+	netdev->do_ioctl = big_sur_ge_ioctl;
+	netdev->tx_timeout = big_sur_ge_tx_timeout;
+	netdev->watchdog_timeo = TX_TIMEOUT;
+	netdev->hard_start_xmit = big_sur_start_xmit;
+	netdev->set_multicast_list = big_sur_ge_set_multi;
+
+	printk(KERN_INFO
+               "%s: PMC-Sierra Big Sur Ethernet Device %d  at 0x%08X mapped to 0x%08X\n",
+		netdev->name, index,
+               lp->save_base_address, config->base_address);
+
+        return 0;
+}
+	
+static int __init big_sur_ge_init(void)
+{
+	int	index = 0;
+
+	while (big_sur_ge_probe(index++) == 0);
+
+	return (index > 1) ? 0 : -ENODEV;
+}
+
+static void __init big_sur_ge_cleanup_module(void)
+{
+	/* Nothing to do here */
+}
+
+module_init(big_sur_ge_init);
+module_exit(big_sur_ge_cleanup_module);
+
diff -urN linux-2.4.29-pre3/drivers/net/big_sur_ge.h linux-2.4.29-rc1/drivers/net/big_sur_ge.h
--- linux-2.4.29-pre3/drivers/net/big_sur_ge.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/big_sur_ge.h	2005-01-12 10:54:50.260664244 -0800
@@ -0,0 +1,449 @@
+/*
+ * drivers/net/big_sur_ge.h - Driver for PMC-Sierra Big Sur
+ * ethernet ports
+ *
+ * Copyright (C) 2003, 2004 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef	__BIG_SUR_GE_H__
+#define	__BIG_SUR_GE_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define	BIG_SUR_DEVICE_NAME	"big sur"
+#define	BIG_SUR_DEVICE_DESC	"Big Sur Ethernet 10/100 MAC"
+
+#define BIG_SUR_GE_BASE		(0x1b000000 | KSEG1)
+
+#define	BIG_SUR_GE_WRITE(ofs,data)			\
+	*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs)) = data
+
+#define	BIG_SUR_GE_READ(ofs)				\
+	*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs))
+
+#define	BIG_SUR_GE_READ_REG(base_addr, reg_offset)	\
+	BIG_SUR_GE_READ(base_addr + reg_offset)
+
+#define	BIG_SUR_GE_WRITE_REG(base_addr, reg_offset, data)	\
+	BIG_SUR_GE_WRITE(base_addr + reg_offset, data)
+
+#define	BIG_SUR_GE_CONTROL_REG(base_addr, mask)		\
+	BIG_SUR_GE_WRITE(base_addr + BIG_SUR_GE_ECR_OFFSET, mask)
+
+#define	BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT	4UL
+
+/* IPIF specific defines */
+#define XIIF_V123B_DISR_OFFSET     0UL  /* device interrupt status register */
+#define XIIF_V123B_DIPR_OFFSET     4UL  /* device interrupt pending register */
+#define XIIF_V123B_DIER_OFFSET     8UL  /* device interrupt enable register */
+#define XIIF_V123B_DIIR_OFFSET     24UL /* device interrupt ID register */
+#define XIIF_V123B_DGIER_OFFSET    28UL /* device global interrupt enable reg */
+#define XIIF_V123B_IISR_OFFSET     32UL /* IP interrupt status register */
+#define XIIF_V123B_IIER_OFFSET     40UL /* IP interrupt enable register */
+#define XIIF_V123B_RESETR_OFFSET   64UL /* reset register */
+#define XIIF_V123B_RESET_MASK	   0xAUL
+#define	XIIF_V123B_ERROR_MASK	   0x1UL
+
+/* Options for the MAC */
+#define BIG_SUR_GE_UNICAST_OPTION        	0x00000001
+#define BIG_SUR_GE_BROADCAST_OPTION      	0x00000002
+#define BIG_SUR_GE_PROMISC_OPTION        	0x00000004
+#define BIG_SUR_GE_FDUPLEX_OPTION        	0x00000008
+#define BIG_SUR_GE_POLLED_OPTION         	0x00000010
+#define BIG_SUR_GE_LOOPBACK_OPTION       	0x00000020
+#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
+#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
+#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
+#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
+#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
+#define BIG_SUR_GE_STRIP_PAD_FCS_OPTION  	0x00002000
+#define BIG_SUR_GE_MULTICAST_OPTION      	0x00000040
+#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
+#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
+#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
+#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
+#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
+#define BIG_SUR_GE_STRIP_PAD_OPTION      	0x00001000
+#define BIG_SUR_GE_STRIP_FCS_OPTION     	0x00002000
+
+#define BIG_SUR_GE_MTU             1500	/* max size of Ethernet frame */
+#define BIG_SUR_GE_HDR_SIZE        14	/* size of Ethernet header */
+#define BIG_SUR_GE_HDR_VLAN_SIZE   18	/* size of Ethernet header with VLAN */
+#define BIG_SUR_GE_TRL_SIZE        4 	/* size of Ethernet trailer (FCS) */
+#define BIG_SUR_GE_MAX_FRAME_SIZE  \
+		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_SIZE + BIG_SUR_GE_TRL_SIZE)
+
+#define BIG_SUR_GE_MAX_VLAN_FRAME_SIZE  \
+		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_VLAN_SIZE + BIG_SUR_GE_TRL_SIZE)
+
+/* FIFO Specific Defines */
+#define BIG_SUR_GE_RESET_REG_OFFSET            0UL
+#define BIG_SUR_GE_MODULE_INFO_REG_OFFSET      0UL
+#define BIG_SUR_GE_COUNT_STATUS_REG_OFFSET     4UL
+#define BIG_SUR_GE_RESET_FIFO_MASK             0x0000000A
+#define BIG_SUR_GE_COUNT_MASK                  0x0000FFFF
+#define BIG_SUR_GE_DEADLOCK_MASK               0x20000000
+#define BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK      0x40000000
+#define BIG_SUR_GE_EMPTY_FULL_MASK             0x80000000
+
+#define BIG_SUR_GE_FIFO_RESET(fifo)				\
+		BIG_SUR_GE_WRITE((fifo)->reg_base_addr + 	\
+		BIG_SUR_GE_RESET_REG_OFFSET, BIG_SUR_GE_RESET_FIFO_MASK)
+
+#define	BIG_SUR_GE_GET_COUNT(fifo)			\
+	(BIG_SUR_GE_READ((fifo)->reg_base_addr + 	\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) & BIG_SUR_GE_COUNT_MASK)
+
+#define	BIG_SUR_GE_IS_ALMOST_EMPTY(fifo)		\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr + 	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &	\
+		BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
+
+#define	BIG_SUR_GE_IS_ALMOST_FULL(fifo)  		\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr + 	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
+		BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
+
+#define BIG_SUR_GE_IS_EMPTY(fifo)  			\
+		(BIG_SUR_GE_READ(fifo->reg_base_addr +	\
+		BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
+		BIG_SUR_GE_EMPTY_FULL_MASK)
+
+#define BIG_SUR_GE_IS_FULL(fifo)  			\
+	(BIG_SUR_GE_READ(fifo->reg_base_addr + 		\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   	\
+	BIG_SUR_GE_EMPTY_FULL_MASK)
+
+#define	BIG_SUR_GE_IS_DEADLOCKED(fifo)			\
+	(BIG_SUR_GE_READ((fifo)->reg_base_addr + 	\
+	BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   	\
+	BIG_SUR_GE_DEADLOCK_MASK)
+
+/* Device Config */
+typedef struct _big_sur_ge_config {
+	u16 device_id;
+	u32 base_address;
+	u32 has_counters;
+	u32 has_sg_dma;
+	u8 dma_config;
+	u32 has_mii;
+} big_sur_ge_config;
+
+/* Send and Receive DMA channel */
+typedef struct _xdma_channel_tag {
+	u32 reg_base_address;
+        u32 base_address;
+        u32 ready;
+} xdma_channel;
+
+/* Send and Receive Packet FIFO */
+typedef struct _packet_fifo {
+        u32 reg_base_addr;
+        u32 ready_status;
+        u32 data_base_address;
+} packet_fifo;
+
+/* Big Sur GE driver structure */
+typedef struct _big_sur_ge {
+	u32 base_address;
+	u32 started;
+	u32 ready;
+	u32 polled;
+	u32 dma_sg;
+	u8 dma_config;
+	u32 has_mii;
+	u32 has_mcast_hash_table;
+	/* For the FIFO and simple DMA case only */
+	packet_fifo recv_fifo;
+	packet_fifo send_fifo;
+	xdma_channel	recv_channel;
+	xdma_channel	send_channel;
+
+	u8 has_dma;
+} big_sur_ge;
+
+/* Offset of the MAC registers from the IPIF base address */
+#define BIG_SUR_GE_REG_OFFSET     0x1100UL
+
+/*
+ * Register offsets for the Ethernet MAC. Each register is 32 bits.
+ */
+#define BIG_SUR_GE_EMIR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x0) /* EMAC Module ID */
+#define BIG_SUR_GE_ECR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x4) /* MAC Control */
+#define BIG_SUR_GE_IFGP_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x8) /* Interframe Gap */
+#define BIG_SUR_GE_SAH_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0xC) /* Station addr, high */
+#define BIG_SUR_GE_SAL_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x10)/* Station addr, low */
+#define BIG_SUR_GE_MGTCR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x14)/* MII mgmt control */
+#define BIG_SUR_GE_MGTDR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x18)/* MII mgmt data */
+#define BIG_SUR_GE_RPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x1C)/* Rx packet length */
+#define BIG_SUR_GE_TPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x20)/* Tx packet length */
+#define BIG_SUR_GE_TSR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x24)/* Tx status */
+#define BIG_SUR_GE_RMFC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x28)/* Rx missed frames */
+#define BIG_SUR_GE_RCC_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x2C)/* Rx collisions */
+#define BIG_SUR_GE_RFCSEC_OFFSET (BIG_SUR_GE_REG_OFFSET + 0x30)/* Rx FCS errors */
+#define BIG_SUR_GE_RAEC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x34)/* Rx alignment errors */
+
+/* Transmit excess deferral cnt */
+#define BIG_SUR_GE_TEDC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x38)
+
+/* Interrupt Status Register */
+#define BIG_SUR_GE_ISR_OFFSET           0x20UL 
+
+/* Send and Receive DMA Channel */
+#define BIG_SUR_GE_DMA_OFFSET           0x2300UL
+#define BIG_SUR_GE_DMA_SEND_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x0) 
+#define BIG_SUR_GE_DMA_RECV_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x40)
+
+/* Packet FIFO */
+#define BIG_SUR_GE_PFIFO_OFFSET         0x2000UL
+#define BIG_SUR_GE_PFIFO_TXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x0) 
+#define BIG_SUR_GE_PFIFO_RXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x10)
+#define BIG_SUR_GE_PFIFO_TXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x100) 
+#define BIG_SUR_GE_PFIFO_RXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x200)
+
+/*
+ * EMAC Module Identification Register (EMIR)
+ */
+#define BIG_SUR_GE_EMIR_VERSION_MASK    0xFFFF0000UL   /* Device version */
+#define BIG_SUR_GE_EMIR_TYPE_MASK       0x0000FF00UL   /* Device type */
+
+/*
+ * EMAC Control Register (ECR)
+ */
+#define BIG_SUR_GE_ECR_FULL_DUPLEX_MASK         0x80000000   /* Full duplex mode */
+#define BIG_SUR_GE_ECR_XMIT_RESET_MASK          0x40000000   /* Reset transmitter */
+#define BIG_SUR_GE_ECR_XMIT_ENABLE_MASK         0x20000000   /* Enable transmitter */
+#define BIG_SUR_GE_ECR_RECV_RESET_MASK          0x10000000   /* Reset receiver */
+#define BIG_SUR_GE_ECR_RECV_ENABLE_MASK         0x08000000   /* Enable receiver */
+#define BIG_SUR_GE_ECR_PHY_ENABLE_MASK          0x04000000   /* Enable PHY */
+#define BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK     0x02000000   /* Enable xmit pad insert */
+#define BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK     0x01000000   /* Enable xmit FCS insert */
+#define BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK    0x00800000   /* Enable xmit source addr insertion */
+#define BIG_SUR_GE_ECR_XMIT_ERROR_INSERT_MASK   0x00400000   /* Insert xmit error */
+#define BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK     0x00200000   /* Enable xmit source addr overwrite */
+#define BIG_SUR_GE_ECR_LOOPBACK_MASK            0x00100000   /* Enable internal loopback */
+#define BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK     0x00080000   /* Enable recv pad strip */
+#define BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK     0x00040000   /* Enable recv FCS strip */
+#define BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK   0x00080000   /* Enable recv pad/fcs strip */
+#define BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK      0x00020000   /* Enable unicast addr */
+#define BIG_SUR_GE_ECR_MULTI_ENABLE_MASK        0x00010000   /* Enable multicast addr */
+#define BIG_SUR_GE_ECR_BROAD_ENABLE_MASK        0x00008000   /* Enable broadcast addr */
+#define BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK      0x00004000   /* Enable promiscuous mode */
+#define BIG_SUR_GE_ECR_RECV_ALL_MASK            0x00002000   /* Receive all frames */
+#define BIG_SUR_GE_ECR_RESERVED2_MASK           0x00001000   /* Reserved */
+#define BIG_SUR_GE_ECR_MULTI_HASH_ENABLE_MASK   0x00000800   /* Enable multicast hash */
+#define BIG_SUR_GE_ECR_PAUSE_FRAME_MASK         0x00000400   /* Interpret pause frames */
+#define BIG_SUR_GE_ECR_CLEAR_HASH_MASK          0x00000200   /* Clear hash table */
+#define BIG_SUR_GE_ECR_ADD_HASH_ADDR_MASK       0x00000100  /* Add hash table address */
+
+/*
+ * Interframe Gap Register (IFGR)
+ */
+#define BIG_SUR_GE_IFGP_PART1_MASK         0xF8000000        /* Interframe Gap Part1 */
+#define BIG_SUR_GE_IFGP_PART1_SHIFT        27
+#define BIG_SUR_GE_IFGP_PART2_MASK         0x07C00000        /* Interframe Gap Part2 */
+#define BIG_SUR_GE_IFGP_PART2_SHIFT        22
+
+/*
+ * Station Address High Register (SAH)
+ */
+#define BIG_SUR_GE_SAH_ADDR_MASK           0x0000FFFF        /* Station address high bytes */
+
+/*
+ * Station Address Low Register (SAL)
+ */
+#define BIG_SUR_GE_SAL_ADDR_MASK           0xFFFFFFFF        /* Station address low bytes */
+
+/*
+ * MII Management Control Register (MGTCR)
+ */
+#define BIG_SUR_GE_MGTCR_START_MASK        0x80000000        /* Start/Busy */
+#define BIG_SUR_GE_MGTCR_RW_NOT_MASK       0x40000000        /* Read/Write Not (direction) */
+#define BIG_SUR_GE_MGTCR_PHY_ADDR_MASK     0x3E000000        /* PHY address */
+#define BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT    25  /* PHY address shift */
+#define BIG_SUR_GE_MGTCR_REG_ADDR_MASK     0x01F00000        /* Register address */
+#define BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT    20  /* Register addr shift */
+#define BIG_SUR_GE_MGTCR_MII_ENABLE_MASK   0x00080000        /* Enable MII from EMAC */
+#define BIG_SUR_GE_MGTCR_RD_ERROR_MASK     0x00040000        /* MII mgmt read error */
+
+/*
+ * MII Management Data Register (MGTDR)
+ */
+#define BIG_SUR_GE_MGTDR_DATA_MASK         0x0000FFFF        /* MII data */
+
+/*
+ * Receive Packet Length Register (RPLR)
+ */
+#define BIG_SUR_GE_RPLR_LENGTH_MASK        0x0000FFFF        /* Receive packet length */
+
+/*
+ * Transmit Packet Length Register (TPLR)
+ */
+#define BIG_SUR_GE_TPLR_LENGTH_MASK        0x0000FFFF       /* Transmit packet length */
+
+/*
+ * Transmit Status Register (TSR)
+ */
+#define BIG_SUR_GE_TSR_EXCESS_DEFERRAL_MASK 0x80000000       /* Transmit excess deferral */
+#define BIG_SUR_GE_TSR_FIFO_UNDERRUN_MASK   0x40000000       /* Packet FIFO underrun */
+#define BIG_SUR_GE_TSR_ATTEMPTS_MASK        0x3E000000      /* Transmission attempts */
+#define BIG_SUR_GE_TSR_LATE_COLLISION_MASK  0x01000000      /* Transmit late collision */
+
+/* Receive Missed Frame Count (RMFC) */
+#define BIG_SUR_GE_RMFC_DATA_MASK          0x0000FFFF
+
+/* Receive Collision Count (RCC) */
+#define BIG_SUR_GE_RCC_DATA_MASK           0x0000FFFF
+
+/* Receive FCS Error Count (RFCSEC) */
+#define BIG_SUR_GE_RFCSEC_DATA_MASK        0x0000FFFF
+
+/* Receive Alignment Error Count (RALN) */
+#define BIG_SUR_GE_RAEC_DATA_MASK          0x0000FFFF
+
+/* Transmit Excess Deferral Count (TEDC) */
+#define BIG_SUR_GE_TEDC_DATA_MASK          0x0000FFFF
+
+/*
+ * EMAC Interrupt Registers (Status and Enable) masks. These registers are
+ * part of the IPIF IP Interrupt registers
+ */
+#define BIG_SUR_GE_EIR_XMIT_DONE_MASK         0x00000001     /* Xmit complete */
+#define BIG_SUR_GE_EIR_RECV_DONE_MASK         0x00000002     /* Recv complete */
+#define BIG_SUR_GE_EIR_XMIT_ERROR_MASK        0x00000004     /* Xmit error */
+#define BIG_SUR_GE_EIR_RECV_ERROR_MASK        0x00000008     /* Recv error */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_EMPTY_MASK  0x00000010     /* Xmit status fifo empty */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK  0x00000020     /* Recv length fifo empty */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK   0x00000040     /* Xmit length fifo full */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK   0x00000080     /* Recv length fifo overrun */
+#define BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK  0x00000100     /* Recv length fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK   0x00000200     /* Xmit status fifo overrun */
+#define BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK  0x00000400     /* Transmit status fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK   0x00000800     /* Transmit length fifo overrun */
+#define BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK  0x00001000     /* Transmit length fifo underrun */
+#define BIG_SUR_GE_EIR_XMIT_PAUSE_MASK        0x00002000     /* Transmit pause pkt received */
+#define BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK   0x00004000     /* Receive data fifo overrun */
+#define BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK 0x00008000     /* Receive missed frame error */
+#define BIG_SUR_GE_EIR_RECV_COLLISION_MASK    0x00010000     /* Receive collision error */
+#define BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK    0x00020000     /* Receive FCS error */
+#define BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK    0x00040000     /* Receive length field error */
+#define BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK  0x00080000     /* Receive short frame error */
+#define BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK   0x00100000     /* Receive long frame error */
+#define BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK  0x00200000     /* Receive alignment error */
+
+/* Enable the MAC unit */
+#define	big_sur_ge_mac_enable(base_address)			\
+{								\
+	u32	control;					\
+	control = BIG_SUR_GE_READ(base_address + 		\
+				BIG_SUR_GE_ECR_OFFSET);		\
+	control &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_RESET_MASK);	\
+	control |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+/* Disable the MAC unit */
+#define	big_sur_ge_mac_disable(base_address)			\
+{								\
+	u32	control;					\
+	control = BIG_SUR_GE_READ(base_address + 		\
+				BIG_SUR_GE_ECR_OFFSET);		\
+	control &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | 		\
+			BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+/* Check if the Tx is done */
+#define	big_sur_ge_tx_done(base_address)			\
+	(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET)	\
+			& BIG_SUR_GE_EIR_XMIT_DONE_MASK)
+
+
+/* Check if Rx FIFO is empty */
+#define	big_sur_ge_rx_empty(base_address)			\
+	(!(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET) \
+			& BIG_SUR_GE_EIR_RECV_DONE_MASK))
+
+/* Reset the MAC PHY */
+#define	big_sur_ge_reset_phy(base_address)				\
+{									\
+	u32 control;							\
+	control = BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ECR_OFFSET);	\
+	control &= ~(BIG_SUR_GE_ECR_PHY_ENABLE_MASK);				\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+	control |= BIG_SUR_GE_ECR_PHY_ENABLE_MASK;				\
+	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);	\
+}
+
+#define BIG_SUR_GE_RST_REG_OFFSET	0  /* reset register */
+#define BIG_SUR_GE_MI_REG_OFFSET	0  /* module information register */
+#define BIG_SUR_GE_DMAC_REG_OFFSET	4  /* DMA control register */
+#define BIG_SUR_GE_SA_REG_OFFSET	8  /* source address register */
+#define BIG_SUR_GE_DA_REG_OFFSET	12 /* destination address register */
+#define BIG_SUR_GE_LEN_REG_OFFSET	16 /* length register */
+#define BIG_SUR_GE_DMAS_REG_OFFSET	20 /* DMA status register */
+#define BIG_SUR_GE_BDA_REG_OFFSET	24 /* buffer descriptor address register */
+#define BIG_SUR_GE_SWCR_REG_OFFSET	28 /* software control register */
+#define BIG_SUR_GE_UPC_REG_OFFSET	32 /* unserviced packet count register */
+#define BIG_SUR_GE_PCT_REG_OFFSET	36 /* packet count threshold register */
+#define BIG_SUR_GE_PWB_REG_OFFSET	40 /* packet wait bound register */
+#define BIG_SUR_GE_IS_REG_OFFSET	44 /* interrupt status register */
+#define BIG_SUR_GE_IE_REG_OFFSET	48 /* interrupt enable register */
+
+#define BIG_SUR_GE_RESET_MASK		0x0000000A
+
+/* Simple DMA register support */
+#define BIG_SUR_GE_DMACR_SOURCE_INCR_MASK	0x80000000UL  /* increment source address */
+#define BIG_SUR_GE_DMACR_DEST_INCR_MASK		0x40000000UL  /* increment dest address */
+#define BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK	0x20000000UL  /* local source address */
+#define BIG_SUR_GE_DMACR_DEST_LOCAL_MASK	0x10000000UL  /* local dest address */
+#define BIG_SUR_GE_DMACR_SG_DISABLE_MASK	0x08000000UL   /* scatter gather disable */
+#define BIG_SUR_GE_DMASR_BUSY_MASK		0x80000000UL  /* channel is busy */
+#define BIG_SUR_GE_DMASR_BUS_ERROR_MASK		0x40000000UL   /* bus error occurred */
+#define BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK	0x20000000UL   /* bus timeout occurred */
+
+/* Interrupts */
+#define BIG_SUR_GE_IPIF_EMAC_MASK      0x00000004UL    /* MAC interrupt */
+#define BIG_SUR_GE_IPIF_SEND_DMA_MASK  0x00000008UL    /* Send DMA interrupt */
+#define BIG_SUR_GE_IPIF_RECV_DMA_MASK  0x00000010UL    /* Receive DMA interrupt */
+#define BIG_SUR_GE_IPIF_RECV_FIFO_MASK 0x00000020UL    /* Receive FIFO interrupt */
+#define BIG_SUR_GE_IPIF_SEND_FIFO_MASK 0x00000040UL    /* Send FIFO interrupt */
+
+#define BIG_SUR_GE_IPIF_FIFO_DFT_MASK  (BIG_SUR_GE_IPIF_EMAC_MASK |	\
+                                 BIG_SUR_GE_IPIF_SEND_FIFO_MASK |	\
+                                 BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
+
+#define BIG_SUR_GE_IPIF_DMA_DEV_INTR_COUNT   7 /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_FIFO_DEV_INTR_COUNT  5 /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_DEVICE_INTR_COUNT  7   /* Number of interrupt sources */
+#define BIG_SUR_GE_IPIF_IP_INTR_COUNT      22  /* Number of MAC interrupts */
+
+/* A default interrupt mask for non-DMA operation (direct FIFOs) */
+#define BIG_SUR_GE_EIR_DFT_FIFO_MASK  (BIG_SUR_GE_EIR_XMIT_DONE_MASK |	\
+                                BIG_SUR_GE_EIR_RECV_DONE_MASK)
+
+#endif
diff -urN linux-2.4.29-pre3/drivers/net/declance.c linux-2.4.29-rc1/drivers/net/declance.c
--- linux-2.4.29-pre3/drivers/net/declance.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/declance.c	2005-01-12 10:54:50.261664287 -0800
@@ -1205,9 +1205,6 @@
 		}
 	}
 
-	lp->next = root_lance_dev;
-	root_lance_dev = dev;
-
 	/* Copy the ethernet address to the device structure, later to the
 	 * lance initialization block so the lance gets it every time it's
 	 * (re)initialized.
@@ -1264,11 +1261,14 @@
 		goto err_out_free_dev;
 	}
 
+	lp->next = root_lance_dev;
+	root_lance_dev = dev;
+
 	printk("%s: registered as %s.\n", name, dev->name);
 	return 0;
 
 err_out_free_dev:
-	kfree(dev);
+	free_netdev(dev);
 
 err_out:
 	return ret;
@@ -1315,13 +1315,13 @@
 		struct net_device *dev = root_lance_dev;
 		struct lance_private *lp = (struct lance_private *)dev->priv;
 
+		unregister_netdev(dev);
 #ifdef CONFIG_TC
 		if (lp->slot >= 0)
 			release_tc_card(lp->slot);
 #endif
 		root_lance_dev = lp->next;
-		unregister_netdev(dev);
-		kfree(dev);
+		free_netdev(dev);
 	}
 }
 
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000.h linux-2.4.29-rc1/drivers/net/e1000/e1000.h
--- linux-2.4.29-pre3/drivers/net/e1000/e1000.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000.h	2005-01-12 10:54:50.265664459 -0800
@@ -86,7 +86,7 @@
 
 #include "e1000_hw.h"
 
-#if DBG
+#ifdef DBG
 #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
 #else
 #define E1000_DBG(args...)
@@ -204,7 +204,7 @@
 	spinlock_t stats_lock;
 	atomic_t irq_sem;
 	struct tq_struct tx_timeout_task;
-     	uint8_t fc_autoneg;
+	uint8_t fc_autoneg;
 
 	struct timer_list blink_timer;
 	unsigned long led_status;
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_ethtool.c linux-2.4.29-rc1/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_ethtool.c	2005-01-12 10:54:46.883519117 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_ethtool.c	2005-01-12 10:54:50.267664545 -0800
@@ -776,7 +776,7 @@
 e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	struct net_device *netdev = adapter->netdev;
- 	uint32_t icr, mask, i=0, shared_int = TRUE;
+ 	uint32_t mask, i=0, shared_int = TRUE;
  	uint32_t irq = adapter->pdev->irq;
 
 	*data = 0;
@@ -784,7 +784,8 @@
 	/* Hook up test interrupt handler just for this test */
  	if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) {
  		shared_int = FALSE;
- 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){
+ 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, 
+			netdev->name, netdev)){
 		*data = 1;
 		return -1;
 	}
@@ -793,21 +794,6 @@
 	E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
 	msec_delay(10);
 
-	/* Interrupts are disabled, so read interrupt cause
-	 * register (icr) twice to verify that there are no interrupts
-	 * pending.  icr is clear on read.
-	 */
-	icr = E1000_READ_REG(&adapter->hw, ICR);
-	icr = E1000_READ_REG(&adapter->hw, ICR);
-
-	if(icr != 0) {
-		/* if icr is non-zero, there is no point
-		 * running other interrupt tests.
-		 */
-		*data = 2;
-		i = 10;
-	}
-
 	/* Test each interrupt */
 	for(; i < 10; i++) {
 
@@ -856,8 +842,10 @@
 			 * test failed.
 			 */
 			adapter->test_icr = 0;
-			E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
-			E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
+			E1000_WRITE_REG(&adapter->hw, IMC, 
+					(~mask & 0x00007FFF));
+			E1000_WRITE_REG(&adapter->hw, ICS, 
+					(~mask & 0x00007FFF));
 			msec_delay(10);
 
 			if(adapter->test_icr) {
@@ -1335,10 +1323,17 @@
 
 	msec_delay(200);
 
-	pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
-			    rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
+	i = 0;
+	do {
+		pci_dma_sync_single(pdev, rxdr->buffer_info[i].dma,
+					    rxdr->buffer_info[i].length,
+					    PCI_DMA_FROMDEVICE);
+
+		if (!e1000_check_lbtest_frame(rxdr->buffer_info[i++].skb, 1024))
+			return 0;
+	} while (i < 64);
 
-	return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
+	return 13;
 }
 
 static int
@@ -1357,10 +1352,27 @@
 e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	*data = 0;
-	e1000_check_for_link(&adapter->hw);
 
-	if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
-		*data = 1;
+	if (adapter->hw.media_type == e1000_media_type_internal_serdes) {
+		int i = 0;
+		adapter->hw.serdes_link_down = TRUE;
+
+		/* on some blade server designs link establishment */
+		/* could take as long as 2-3 minutes.              */
+		do {
+			e1000_check_for_link(&adapter->hw);
+			if (adapter->hw.serdes_link_down == FALSE)
+				return *data;
+			msec_delay(20);
+		} while (i++ < 3750);
+
+		*data = 1; 
+	} else {
+		e1000_check_for_link(&adapter->hw);
+
+		if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+			*data = 1;
+		}
 	}
 	return *data;
 }
@@ -1489,6 +1501,8 @@
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
 	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+	case E1000_DEV_ID_82545EM_COPPER:
 		return wol->wolopts ? -EOPNOTSUPP : 0;
 
 	case E1000_DEV_ID_82546EB_FIBER:
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_hw.c linux-2.4.29-rc1/drivers/net/e1000/e1000_hw.c
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_hw.c	2005-01-12 10:54:46.887519289 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_hw.c	2005-01-12 10:54:50.271664717 -0800
@@ -123,17 +123,31 @@
 static void
 e1000_phy_init_script(struct e1000_hw *hw)
 {
+    uint32_t ret_val;
+    uint16_t phy_saved_data;
+
     DEBUGFUNC("e1000_phy_init_script");
 
-    
+
     if(hw->phy_init_script) {
         msec_delay(20);
 
+        /* Save off the current value of register 0x2F5B to be restored at
+         * the end of this routine. */
+        ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+        /* Disabled the PHY transmitter */
+        e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+        msec_delay(20);
+
         e1000_write_phy_reg(hw,0x0000,0x0140);
 
         msec_delay(5);
 
-        if(hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547) {
+        switch(hw->mac_type) {
+        case e1000_82541:
+        case e1000_82547:
             e1000_write_phy_reg(hw, 0x1F95, 0x0001);
 
             e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
@@ -151,12 +165,23 @@
             e1000_write_phy_reg(hw, 0x1F96, 0x003F);
 
             e1000_write_phy_reg(hw, 0x2010, 0x0008);
-        } else {
+            break;
+
+        case e1000_82541_rev_2:
+        case e1000_82547_rev_2:
             e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+            break;
+        default:
+            break;
         }
 
         e1000_write_phy_reg(hw, 0x0000, 0x3300);
 
+        msec_delay(20);
+
+        /* Now enable the transmitter */
+        e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
         if(hw->mac_type == e1000_82547) {
             uint16_t fused, fine, coarse;
 
@@ -245,6 +270,7 @@
     case E1000_DEV_ID_82546GB_COPPER:
     case E1000_DEV_ID_82546GB_FIBER:
     case E1000_DEV_ID_82546GB_SERDES:
+    case E1000_DEV_ID_82546GB_PCIE:
         hw->mac_type = e1000_82546_rev_3;
         break;
     case E1000_DEV_ID_82541EI:
@@ -968,7 +994,7 @@
 
             if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
                 hw->dsp_config_state = e1000_dsp_config_disabled;
-                /* Force MDI for IGP B-0 PHY */
+                /* Force MDI for earlier revs of the IGP PHY */
                 phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
                               IGP01E1000_PSCR_FORCE_MDI_MDIX);
                 hw->mdix = 1;
@@ -2113,7 +2139,7 @@
          * at gigabit speed, then TBI compatibility is not needed.  If we are
          * at gigabit speed, we turn on TBI compatibility.
          */
-	if(hw->tbi_compatibility_en) {
+        if(hw->tbi_compatibility_en) {
             uint16_t speed, duplex;
             e1000_get_speed_and_duplex(hw, &speed, &duplex);
             if(speed != SPEED_1000) {
@@ -2473,8 +2499,9 @@
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
-        if(ret_val)
+        if(ret_val) {
             return ret_val;
+        }
     }
 
     ret_val = e1000_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
@@ -2578,8 +2605,9 @@
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
                                          (uint16_t)reg_addr);
-        if(ret_val)
+        if(ret_val) {
             return ret_val;
+        }
     }
 
     ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
@@ -3482,7 +3510,7 @@
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
@@ -3628,11 +3656,10 @@
 
     DEBUGFUNC("e1000_write_eeprom");
 
-
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
@@ -4924,7 +4951,7 @@
                                    boolean_t link_up)
 {
     int32_t ret_val;
-    uint16_t phy_data, speed, duplex, i;
+    uint16_t phy_data, phy_saved_data, speed, duplex, i;
     uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
                                         {IGP01E1000_PHY_AGC_PARAM_A,
                                         IGP01E1000_PHY_AGC_PARAM_B,
@@ -5005,6 +5032,21 @@
         }
     } else {
         if(hw->dsp_config_state == e1000_dsp_config_activated) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay(20);
+
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
             if(ret_val)
@@ -5027,10 +5069,33 @@
             if(ret_val)
                 return ret_val;
 
+            msec_delay(20);
+
+            /* Now enable the transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
             hw->dsp_config_state = e1000_dsp_config_enabled;
         }
 
         if(hw->ffe_config_state == e1000_ffe_config_active) {
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay(20);
+
             ret_val = e1000_write_phy_reg(hw, 0x0000,
                                           IGP01E1000_IEEE_FORCE_GIGA);
             if(ret_val)
@@ -5044,6 +5109,15 @@
                                           IGP01E1000_IEEE_RESTART_AUTONEG);
             if(ret_val)
                 return ret_val;
+
+            msec_delay(20);
+
+            /* Now enable the transmitter */
+            ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
             hw->ffe_config_state = e1000_ffe_config_enabled;
         }
     }
@@ -5132,14 +5206,29 @@
          * Dx states where the power conservation is most important.  During
          * driver activity we should enable SmartSpeed, so performance is
          * maintained. */
-        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
-        if(ret_val)
-            return ret_val;
+        if (hw->smart_speed == e1000_smart_speed_on) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
 
-        phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
-        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
-        if(ret_val)
-            return ret_val;
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == e1000_smart_speed_off) {
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+	    if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
 
     } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_hw.h linux-2.4.29-rc1/drivers/net/e1000/e1000_hw.h
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_hw.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_hw.h	2005-01-12 10:54:50.274664846 -0800
@@ -169,6 +169,12 @@
 } e1000_downshift;
 
 typedef enum {
+    e1000_smart_speed_default = 0,
+    e1000_smart_speed_on,
+    e1000_smart_speed_off
+} e1000_smart_speed;
+
+typedef enum {
     e1000_polarity_reversal_enabled = 0,
     e1000_polarity_reversal_disabled,
     e1000_polarity_reversal_undefined = 0xFF
@@ -362,6 +368,7 @@
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82547EI             0x1019
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -1027,6 +1034,7 @@
     uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
     boolean_t disable_polarity_correction;
     boolean_t speed_downgraded;
+    e1000_smart_speed smart_speed;
     e1000_dsp_config dsp_config_state;
     boolean_t get_link_status;
     boolean_t serdes_link_down;
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_main.c linux-2.4.29-rc1/drivers/net/e1000/e1000_main.c
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_main.c	2005-01-12 10:54:46.889519375 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_main.c	2005-01-12 10:54:50.276664932 -0800
@@ -34,11 +34,15 @@
  * - if_mii support and associated kcompat for older kernels
  * - More errlogging support from Jon Mason <jonmason@us.ibm.com>
  * - Fix TSO issues on PPC64 machines -- Jon Mason <jonmason@us.ibm.com>
- *
- * 5.3.11	6/4/04
- * - ethtool register dump reads MANC register conditionally.
- *
- * 5.3.10	6/1/04
+ * 5.6.5 	11/01/04
+ * - Enabling NETIF_F_SG without checksum offload is illegal - 
+     John Mason <jdmason@us.ibm.com>
+ * 5.6.3        10/26/04
+ * - Remove redundant initialization - Jamal Hadi
+ * - Reset buffer_info->dma in tx resource cleanup logic
+ * 5.6.2	10/12/04
+ * - Sparse cleanup - shemminger@osdl.org
+ * - Fix tx resource cleanup logic
  */
 
 char e1000_driver_name[] = "e1000";
@@ -48,7 +52,7 @@
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-char e1000_driver_version[] = "5.5.4-k1"DRIVERNAPI;
+char e1000_driver_version[] = "5.6.10.1-k1"DRIVERNAPI;
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -90,6 +94,7 @@
 	INTEL_E1000_ETHERNET_DEVICE(0x107A),
 	INTEL_E1000_ETHERNET_DEVICE(0x107B),
 	INTEL_E1000_ETHERNET_DEVICE(0x107C),
+	INTEL_E1000_ETHERNET_DEVICE(0x108A),
 	/* required last entry */
 	{0,}
 };
@@ -128,8 +133,6 @@
 static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
 static int e1000_set_mac(struct net_device *netdev, void *p);
-static void e1000_irq_disable(struct e1000_adapter *adapter);
-static void e1000_irq_enable(struct e1000_adapter *adapter);
 static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
 static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
 #ifdef CONFIG_E1000_NAPI
@@ -146,9 +149,6 @@
 void set_ethtool_ops(struct net_device *netdev);
 static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
 static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
-static void e1000_rx_checksum(struct e1000_adapter *adapter,
-                              struct e1000_rx_desc *rx_desc,
-                              struct sk_buff *skb);
 static void e1000_tx_timeout(struct net_device *dev);
 static void e1000_tx_timeout_task(struct net_device *dev);
 static void e1000_smartspeed(struct e1000_adapter *adapter);
@@ -242,6 +242,33 @@
 
 module_exit(e1000_exit_module);
 
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_disable(struct e1000_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq();
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
+		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
+		E1000_WRITE_FLUSH(&adapter->hw);
+	}
+}
 
 int
 e1000_up(struct e1000_adapter *adapter)
@@ -475,8 +502,6 @@
 				   NETIF_F_HW_VLAN_TX |
 				   NETIF_F_HW_VLAN_RX |
 				   NETIF_F_HW_VLAN_FILTER;
-	} else {
-		netdev->features = NETIF_F_SG;
 	}
 
 #ifdef NETIF_F_TSO
@@ -1056,6 +1081,24 @@
 	adapter->tx_ring.desc = NULL;
 }
 
+static inline void
+e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
+			struct e1000_buffer *buffer_info)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	if(buffer_info->dma) {
+		pci_unmap_page(pdev,
+			       buffer_info->dma,
+			       buffer_info->length,
+			       PCI_DMA_TODEVICE);
+		buffer_info->dma = 0;
+	}
+	if(buffer_info->skb) {
+		dev_kfree_skb_any(buffer_info->skb);
+		buffer_info->skb = NULL;
+	}
+}
+
 /**
  * e1000_clean_tx_ring - Free Tx Buffers
  * @adapter: board private structure
@@ -1066,7 +1109,6 @@
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 	struct e1000_buffer *buffer_info;
-	struct pci_dev *pdev = adapter->pdev;
 	unsigned long size;
 	unsigned int i;
 
@@ -1074,17 +1116,7 @@
 
 	for(i = 0; i < tx_ring->count; i++) {
 		buffer_info = &tx_ring->buffer_info[i];
-		if(buffer_info->skb) {
-
-			pci_unmap_page(pdev,
-				       buffer_info->dma,
-				       buffer_info->length,
-				       PCI_DMA_TODEVICE);
-
-			dev_kfree_skb(buffer_info->skb);
-
-			buffer_info->skb = NULL;
-		}
+		e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 	}
 
 	size = sizeof(struct e1000_buffer) * tx_ring->count;
@@ -1262,9 +1294,12 @@
 	uint32_t rctl;
 	uint32_t hash_value;
 	int i;
+	unsigned long flags;
 
 	/* Check for Promiscuous and All Multicast modes */
 
+	spin_lock_irqsave(&adapter->tx_lock, flags);
+
 	rctl = E1000_READ_REG(hw, RCTL);
 
 	if(netdev->flags & IFF_PROMISC) {
@@ -1313,6 +1348,8 @@
 
 	if(hw->mac_type == e1000_82542_rev2_0)
 		e1000_leave_82542_rst(adapter);
+
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 }
 
 /* Need to wait a few seconds after link up to get diagnostic information from
@@ -1752,7 +1789,6 @@
 	unsigned int mss = 0;
 	int count = 0;
 	unsigned int f;
-	nr_frags = skb_shinfo(skb)->nr_frags;
 	len -= skb->data_len;
 
 	if(unlikely(skb->len <= 0)) {
@@ -1796,22 +1832,22 @@
 
 	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
+	if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) {
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&adapter->tx_lock, flags);
 		return 1;
 	}
 
-	spin_unlock_irqrestore(&adapter->tx_lock, flags);
-
 	if(unlikely(adapter->hw.mac_type == e1000_82547)) {
 		if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
 			return 1;
+			spin_unlock_irqrestore(&adapter->tx_lock, flags);
 		}
 	}
 
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 	if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
 		tx_flags |= E1000_TX_FLAGS_VLAN;
 		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
@@ -1889,9 +1925,9 @@
 	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
 	if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
-	   (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-		DPRINTK(PROBE, ERR, "Invalid MTU setting\n");
-		return -EINVAL;
+		(max_frame > MAX_JUMBO_FRAME_SIZE)) {
+			DPRINTK(PROBE, ERR, "Invalid MTU setting\n");
+			return -EINVAL;
 	}
 
 	if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) {
@@ -2059,34 +2095,6 @@
 }
 
 /**
- * e1000_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-
-static void
-e1000_irq_disable(struct e1000_adapter *adapter)
-{
-	atomic_inc(&adapter->irq_sem);
-	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
-	E1000_WRITE_FLUSH(&adapter->hw);
-	synchronize_irq();
-}
-
-/**
- * e1000_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-
-static void
-e1000_irq_enable(struct e1000_adapter *adapter)
-{
-	if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
-		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
-		E1000_WRITE_FLUSH(&adapter->hw);
-	}
-}
-
-/**
  * e1000_intr - Interrupt Handler
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
@@ -2147,6 +2155,9 @@
 	int tx_cleaned;
 	int work_done = 0;
 	
+	if (!netif_carrier_ok(netdev))
+		goto quit_polling;
+
 	tx_cleaned = e1000_clean_tx_irq(adapter);
 	e1000_clean_rx_irq(adapter, &work_done, work_to_do);
 
@@ -2156,7 +2167,7 @@
 	/* if no Rx and Tx cleanup work was done, exit the polling mode */
 	if(!tx_cleaned || (work_done < work_to_do) || 
 				!netif_running(netdev)) {
-		netif_rx_complete(netdev);
+quit_polling:	netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
 		return 0;
 	}
@@ -2175,7 +2186,6 @@
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_tx_desc *tx_desc, *eop_desc;
 	struct e1000_buffer *buffer_info;
 	unsigned int i, eop;
@@ -2190,20 +2200,7 @@
 			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
 
-			if(likely(buffer_info->dma)) {
-				pci_unmap_page(pdev,
-					       buffer_info->dma,
-					       buffer_info->length,
-					       PCI_DMA_TODEVICE);
-
-				buffer_info->dma = 0;
-			}
-
-			if(buffer_info->skb) {
-				dev_kfree_skb_any(buffer_info->skb);
-				buffer_info->skb = NULL;
-			}
-
+			e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 			tx_desc->buffer_addr = 0;
 			tx_desc->lower.data = 0;
 			tx_desc->upper.data = 0;
@@ -2230,6 +2227,41 @@
 }
 
 /**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+e1000_rx_checksum(struct e1000_adapter *adapter,
+                  struct e1000_rx_desc *rx_desc,
+                  struct sk_buff *skb)
+{
+	/* 82543 or newer only */
+	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
+	/* Ignore Checksum bit is set */
+	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
+	/* TCP Checksum has not been calculated */
+	(!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* At this point we know the hardware did the TCP checksum */
+	/* now look at the TCP checksum error bit */
+	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
+		/* let the stack verify checksum errors */
+		skb->ip_summed = CHECKSUM_NONE;
+		adapter->hw_csum_err++;
+	} else {
+		/* TCP checksum is good */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->hw_csum_good++;
+	}
+}
+
+/**
  * e1000_clean_rx_irq - Send received data up the network stack
  * @adapter: board private structure
  **/
@@ -2277,7 +2309,7 @@
 		if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) {
 			/* All receives must fit into a single buffer */
 			E1000_DBG("%s: Receive packet consumed multiple"
-				  " buffers\n", netdev->name);
+					" buffers\n", netdev->name);
 			dev_kfree_skb_irq(skb);
 			goto next_desc;
 		}
@@ -2575,41 +2607,6 @@
 	return E1000_SUCCESS;
 }
 
-/**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
- * @adapter: board private structure
- * @rx_desc: receive descriptor
- * @sk_buff: socket buffer with received data
- **/
-
-static void
-e1000_rx_checksum(struct e1000_adapter *adapter,
-                  struct e1000_rx_desc *rx_desc,
-                  struct sk_buff *skb)
-{
-	/* 82543 or newer only */
-	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
-	/* Ignore Checksum bit is set */
-	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
-	/* TCP Checksum has not been calculated */
-	(!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) {
-		skb->ip_summed = CHECKSUM_NONE;
-		return;
-	}
-
-	/* At this point we know the hardware did the TCP checksum */
-	/* now look at the TCP checksum error bit */
-	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
-		/* let the stack verify checksum errors */
-		skb->ip_summed = CHECKSUM_NONE;
-		adapter->hw_csum_err++;
-	} else {
-		/* TCP checksum is good */
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		adapter->hw_csum_good++;
-	}
-}
-
 void
 e1000_pci_set_mwi(struct e1000_hw *hw)
 {
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_osdep.h linux-2.4.29-rc1/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_osdep.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_osdep.h	2005-01-12 10:54:50.277664975 -0800
@@ -69,7 +69,7 @@
 
 #define MSGOUT(S, A, B)	printk(KERN_DEBUG S "\n", A, B)
 
-#if DBG
+#ifdef DBG
 #define DEBUGOUT(S)		printk(KERN_DEBUG S "\n")
 #define DEBUGOUT1(S, A...)	printk(KERN_DEBUG S "\n", A)
 #else
diff -urN linux-2.4.29-pre3/drivers/net/e1000/e1000_param.c linux-2.4.29-rc1/drivers/net/e1000/e1000_param.c
--- linux-2.4.29-pre3/drivers/net/e1000/e1000_param.c	2005-01-12 10:54:46.890519418 -0800
+++ linux-2.4.29-rc1/drivers/net/e1000/e1000_param.c	2005-01-12 10:54:50.278665018 -0800
@@ -447,9 +447,6 @@
 
 			adapter->itr = InterruptThrottleRate[bd];
 			switch(adapter->itr) {
-			case -1:
-				adapter->itr = 1;
-				break;
 			case 0:
 				DPRINTK(PROBE, INFO, "%s turned off\n", 
 					opt.name);
@@ -458,6 +455,7 @@
 				DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", 
 					opt.name);
 				break;
+			case -1:
 			default:
 				e1000_validate_option(&adapter->itr, &opt, 
 					adapter);
diff -urN linux-2.4.29-pre3/drivers/net/gt64240eth.c linux-2.4.29-rc1/drivers/net/gt64240eth.c
--- linux-2.4.29-pre3/drivers/net/gt64240eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/gt64240eth.c	2005-01-12 10:54:50.285665318 -0800
@@ -29,6 +29,9 @@
  *
  * Support for Rx NAPI, Rx checksum offload, IOCTL and ETHTOOL added
  * Manish Lachwani (lachwani@pmc-sierra.com) - 09/16/2003
+ *
+ * Modified for later version of Linux 2.4 kernel
+ * Manish Lachwani (lachwani@pmc-sierra.com) - 04/29/2004
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -77,12 +80,20 @@
  *  > 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
 
+static int debug = -1;
+
+#define GT64240_MSG_ENABLE	(NETIF_MSG_DRV          | \
+				NETIF_MSG_PROBE        | \
+				NETIF_MSG_LINK)
+
+
 /********************************************************/
 
 // prototypes
@@ -254,119 +265,84 @@
 	return (int) (smir & smirDataMask);
 }
 
-/* Ethtool support */
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void gp_get_drvinfo (struct net_device *dev, 
+				struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, "gt64260");
+	strcpy(info->version, version);
+}
+
+static int gp_get_settings(struct net_device *dev, 
+				struct ethtool_cmd *cmd)
 {
 	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
-	u32 ethcmd;
+	int rc;
 
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
+	spin_lock_irq(&gp->lock);
+	rc = mii_ethtool_gset(&gp->mii_if, cmd);
+	spin_unlock_irq(&gp->lock);
+	return rc;
+}
 
-	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 gp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	int rc;
+
+	spin_lock_irq(&gp->lock);
+	rc = mii_ethtool_sset(&gp->mii_if, cmd);
+	spin_unlock_irq(&gp->lock);
+	return rc;
 }
 
+static int gp_nway_reset(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return mii_nway_restart(&gp->mii_if);
+}
+
+static u32 gp_get_link(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return mii_link_ok(&gp->mii_if);
+}
+
+static u32 gp_get_msglevel(struct net_device *dev)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	return gp->msg_enable;
+}
+
+static void gp_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
+	gp->msg_enable = value;
+}
+
+static struct ethtool_ops gp_ethtool_ops = {
+	.get_drvinfo		= gp_get_drvinfo,
+	.get_settings		= gp_get_settings,
+	.set_settings		= gp_set_settings,
+	.nway_reset		= gp_nway_reset,
+	.get_link		= gp_get_link,
+	.get_msglevel		= gp_get_msglevel,
+	.set_msglevel		= gp_set_msglevel,
+};
+
 static int gt64240_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct gt64240_private *gp = (struct gt64240_private *) dev->priv;
 	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;
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irq(&gp->lock);
+	retval = generic_mii_ioctl(&gp->mii_if, data, cmd, NULL);
+	spin_unlock_irq(&gp->lock);
 
-	default:
-		retval = -EOPNOTSUPP;
-		break;
-	}
 	return retval;
 }
 
@@ -714,17 +690,6 @@
 	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.
  */
@@ -770,21 +735,12 @@
 	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);
+	dev = alloc_etherdev(sizeof(struct gt64240_private));
+	if (!dev)
+		return -ENOMEM;
 
 	if (irq < 0) {
 		printk
@@ -801,12 +757,8 @@
 	       (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));
+	    ("%s: GT64240 found at ioaddr 0x%lx, irq %d.\n",
+	     dev->name, ioaddr, irq);
 
 	if (gt64240_debug && version_printed++ == 0)
 		printk("%s: %s", dev->name, version);
@@ -821,23 +773,9 @@
 	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->msg_enable = (debug < 0 ? GT64240_MSG_ENABLE : debug);
 	gp->port_num = port_num;
 	gp->io_size = GT64240_ETH_IO_SIZE;
 	gp->port_offset = port_num * GT64240_ETH_IO_SIZE;
@@ -927,12 +865,12 @@
 	dev->poll = gt64240_poll;
 	dev->weight = 64;
 #endif
+	dev->ethtool_ops = &gp_ethtool_ops;
 
 	/* Fill in the fields of the device structure with ethernet values. */
-	ether_setup(dev);
 	return 0;
 
-      free_region:
+free_region:
 	release_region(ioaddr, gp->io_size);
 	unregister_netdev(dev);
 	if (dev->priv != NULL)
@@ -1036,7 +974,6 @@
 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);
@@ -1292,7 +1229,7 @@
 	    (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);
+	u32 status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
 
 	spin_lock_irqsave(&gp->lock, flags);
 	gt64240_tx_fill(netdev, status);
@@ -1315,6 +1252,8 @@
 	}
 
 	spin_unlock_irqrestore(&gp->lock, flags);
+
+	return (done ? 0 : 1);
 }
 #endif
 
diff -urN linux-2.4.29-pre3/drivers/net/gt64240eth.h linux-2.4.29-rc1/drivers/net/gt64240eth.h
--- linux-2.4.29-pre3/drivers/net/gt64240eth.h	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/gt64240eth.h	2005-01-12 10:54:50.286665361 -0800
@@ -401,6 +401,8 @@
     int drv_flags;
     spinlock_t lock;	   /* Serialise access to device */
     struct mii_if_info mii_if;
+
+    u32	msg_enable;
 };
 
 #endif /* _GT64240ETH_H */
diff -urN linux-2.4.29-pre3/drivers/net/jazzsonic.c linux-2.4.29-rc1/drivers/net/jazzsonic.c
--- linux-2.4.29-pre3/drivers/net/jazzsonic.c	2001-09-09 10:43:01.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/jazzsonic.c	2005-01-12 10:54:50.289665490 -0800
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -51,8 +52,8 @@
 
 #define SONIC_WRITE(reg,val)						\
 do {									\
-	*((volatile unsigned int *)base_addr+reg) = val;		\
-}
+	*((volatile unsigned int *)base_addr+(reg)) = (val);		\
+} while (0)
 
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -84,7 +85,7 @@
 /* Index to functions, as function prototypes. */
 
 extern int sonic_probe(struct net_device *dev);
-static int sonic_probe1(struct net_device *dev, unsigned int base_addr,
+static int sonic_probe1(struct net_device *dev, unsigned long base_addr,
                         unsigned int irq);
 
 
@@ -94,7 +95,7 @@
  */
 int __init sonic_probe(struct net_device *dev)
 {
-	unsigned int base_addr = dev ? dev->base_addr : 0;
+	unsigned long base_addr = dev ? dev->base_addr : 0;
 	int i;
 
 	/*
@@ -117,7 +118,7 @@
 	return -ENODEV;
 }
 
-static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
+static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
                                unsigned int irq)
 {
 	static unsigned version_printed;
diff -urN linux-2.4.29-pre3/drivers/net/mv64340_eth.c linux-2.4.29-rc1/drivers/net/mv64340_eth.c
--- linux-2.4.29-pre3/drivers/net/mv64340_eth.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/mv64340_eth.c	2005-01-12 10:54:50.291665576 -0800
@@ -94,13 +94,6 @@
  * 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;
@@ -707,11 +700,11 @@
 	if (mv64340_eth_real_open(dev)) {
 		printk("%s: Error opening interface\n", dev->name);
 		free_irq(dev->irq, dev);
-		spin_unlock_irq(&ethernet_priv->lock);
+               spin_unlock_irq(&port_private->lock);
 		return -EBUSY;
 	}
 	MOD_INC_USE_COUNT;
-	spin_unlock_irq(&ethernet_priv->lock);
+       spin_unlock_irq(&port_private->lock);
 	return 0;
 }
 
@@ -723,7 +716,6 @@
 	unsigned int port_num;
 	u32 phy_reg_data;
 	unsigned int size;
-	int i;
 
 	ethernet_private = dev->priv;
 	port_private =
@@ -952,7 +944,7 @@
 
 	free_irq(dev->irq, dev);
 	MOD_DEC_USE_COUNT;
-	spin_unlock_irq(&ethernet_priv->lock);
+       spin_unlock_irq(&port_private->lock);
 	return 0;
 };
 
@@ -1232,7 +1224,7 @@
 	stats->tx_packets++;
 	dev->trans_start = jiffies;
 
-	spin_unlock_irqrestore(&ethernet_priv->lock, flags);
+       spin_unlock_irqrestore(&port_private->lock, flags);
 	return 0;		/* success */
 }
 
@@ -2874,6 +2866,8 @@
 	return ETH_OK;
 }
 
+#ifdef MV64340_COAL
+
 /*******************************************************************************
  * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path
  *
@@ -2910,6 +2904,7 @@
 		  & 0xffc000ff));
 	return coal;
 }
+#endif
 
 /*******************************************************************************
  * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path
diff -urN linux-2.4.29-pre3/drivers/net/ne.c linux-2.4.29-rc1/drivers/net/ne.c
--- linux-2.4.29-pre3/drivers/net/ne.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.29-rc1/drivers/net/ne.c	2005-01-12 10:54:50.292665619 -0800
@@ -105,6 +105,9 @@
     {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
     {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
     {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
+#ifdef CONFIG_TOSHIBA_RBTX4927
+    {"TX4927", "TX4927", {0x00, 0x60, 0x0a}}, /* Toshiba w/EEPROM, no probing */
+#endif
     {0,}
 };
 #endif
@@ -239,6 +242,13 @@
 	int reg0, ret;
 	static unsigned version_printed;
 
+#ifdef CONFIG_TOSHIBA_RBTX4927
+#include <asm/tx4927/toshiba_rbtx4927.h>
+	ioaddr = RBTX4927_RTL_8019_BASE;
+	dev->irq = RBTX4927_RTL_8019_IRQ;
+	wordlength = 1;
+#endif
+
 	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
 		return -EBUSY;
 
@@ -342,8 +352,15 @@
 		start_page = NESM_START_PG;
 		stop_page = NESM_STOP_PG;
 	} else {
+#ifdef CONFIG_TOSHIBA_RBTX4927
+		start_page = NESM_START_PG;
+		stop_page = NESM_STOP_PG;
+		for (i = 0; i < 16; i++)
+			SA_prom[i] = SA_prom[i+i];
+#else
 		start_page = NE1SM_START_PG;
 		stop_page = NE1SM_STOP_PG;
+#endif
 	}
 
 	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
diff -urN linux-2.4.29-pre3/drivers/net/pcnet32.c linux-2.4.29-rc1/drivers/net/pcnet32.c
--- linux-2.4.29-pre3/drivers/net/pcnet32.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/pcnet32.c	2005-01-12 10:54:50.294665705 -0800
@@ -1007,7 +1007,11 @@
 	return -EBUSY;
     }
 
-    return pcnet32_probe1(ioaddr, 1, pdev);
+    err = pcnet32_probe1(ioaddr, 1, pdev);
+    if (err < 0) {
+	pci_disable_device(pdev);
+    }
+    return err;
 }
 
 
@@ -2241,6 +2245,7 @@
 	release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
 	pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	free_netdev(dev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
     }
 }
diff -urN linux-2.4.29-pre3/drivers/net/sb1250-mac.c linux-2.4.29-rc1/drivers/net/sb1250-mac.c
--- linux-2.4.29-pre3/drivers/net/sb1250-mac.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/sb1250-mac.c	2005-01-12 10:54:50.298665877 -0800
@@ -468,14 +468,17 @@
 {
 	int cnt;
 	uint64_t bits;
+	int mac_mdio_genc;
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
 	
 	bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
 	
-	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	
 	for (cnt = 0; cnt < 32; cnt++) {
-		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
-		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	}
 }
 
@@ -496,9 +499,12 @@
 	int i;
 	uint64_t bits;
 	unsigned int curmask;
+	int mac_mdio_genc;
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
 	
 	bits = M_MAC_MDIO_DIR_OUTPUT;
-	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 	
 	curmask = 1 << (bitcnt - 1);
 	
@@ -506,9 +512,9 @@
 		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);
-		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
 		curmask >>= 1;
 	}
 }
@@ -534,7 +540,8 @@
 	int idx;
 	int error;
 	int regval;
-	
+	int mac_mdio_genc;
+
 	/*
 	 * Synchronize ourselves so that the PHY knows the next
 	 * thing coming down is a command
@@ -555,17 +562,20 @@
 	sbmac_mii_senddata(s,phyaddr, 5);
 	sbmac_mii_senddata(s,regidx, 5);
 	
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
+	
 	/* 
 	 * Switch the port around without a clock transition.
 	 */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	/*
 	 * Send out a clock pulse to signal we want the status
 	 */
 	
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,
+		       M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	/* 
 	 * If an error occurred, the PHY will signal '1' back
@@ -576,8 +586,9 @@
 	 * Issue an 'idle' clock pulse, but keep the direction
 	 * the same.
 	 */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,
+		       M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	
 	regval = 0;
 	
@@ -589,12 +600,14 @@
 				regval |= 1;
 		}
 		
-		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
-		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+		SBMAC_WRITECSR(s->sbm_mdio,
+			       M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc);
+		SBMAC_WRITECSR(s->sbm_mdio,
+			       M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
 	}
 	
 	/* Switch back to output */
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
 	
 	if (error == 0)
 		return regval;
@@ -620,7 +633,8 @@
 static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
 			    unsigned int regval)
 {
-	
+	int mac_mdio_genc;
+
 	sbmac_mii_sync(s);
 	
 	sbmac_mii_senddata(s,MII_COMMAND_START,2);
@@ -629,8 +643,10 @@
 	sbmac_mii_senddata(s,regidx, 5);
 	sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
 	sbmac_mii_senddata(s,regval,16);
-	
-	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+
+	mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
+
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
 }
 
 
@@ -2788,7 +2804,7 @@
 	struct net_device *dev;
 	sbmac_port_t port;
 	int chip_max_units;
-	
+
 	/*
 	 * For bringup when not using the firmware, we can pre-fill
 	 * the MAC addresses using the environment variables
diff -urN linux-2.4.29-pre3/drivers/net/sgiseeq.c linux-2.4.29-rc1/drivers/net/sgiseeq.c
--- linux-2.4.29-pre3/drivers/net/sgiseeq.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/sgiseeq.c	2005-01-12 10:54:50.299665920 -0800
@@ -162,12 +162,6 @@
 
 	seeq_load_eaddr(dev, sp->sregs);
 
-	/* XXX for now just accept packets directly to us
-	 * XXX and ether-broadcast.  Will do multicast and
-	 * XXX promiscuous mode later. -davem
-	 */
-	sp->mode = SEEQ_RCMD_RBCAST;
-
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
 		if (!ib->tx_desc[i].tdma.pbuf) {
@@ -332,10 +326,17 @@
 				/* Copy out of kseg1 to avoid silly cache flush. */
 				eth_copy_and_sum(skb, pkt_pointer + 2, len, 0);
 				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				sp->stats.rx_packets++;
-				sp->stats.rx_bytes += len;
+
+				/* We don't want to receive our own packets */
+				if (memcmp(skb->mac.ethernet->h_source, dev->dev_addr, 6)) {
+					netif_rx(skb);
+					dev->last_rx = jiffies;
+					sp->stats.rx_packets++;
+					sp->stats.rx_bytes += len;
+				} else {
+					/* Silently drop my own packets */
+					dev_kfree_skb_irq(skb);
+				}
 			} else {
 				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
@@ -570,6 +571,22 @@
 
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
+	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	unsigned char oldmode = sp->mode;
+
+	if(dev->flags & IFF_PROMISC)
+		sp->mode = SEEQ_RCMD_RANY;
+	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count)
+		sp->mode = SEEQ_RCMD_RBMCAST;
+	else
+		sp->mode = SEEQ_RCMD_RBCAST;
+
+	/* XXX I know this sucks, but is there a better way to reprogram
+	 * XXX the receiver? At least, this shouldn't happen too often.
+	 */
+
+	if (oldmode != sp->mode)
+		sgiseeq_reset(dev);
 }
 
 static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
@@ -640,6 +657,7 @@
 	sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
 	sp->hregs = &hpc3c0->ethregs;
 	sp->name = sgiseeqstr;
+	sp->mode = SEEQ_RCMD_RBCAST;
 
 	sp->srings.rx_desc = (struct sgiseeq_rx_desc *)
 	                     KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]));
diff -urN linux-2.4.29-pre3/drivers/net/titan_ge.c linux-2.4.29-rc1/drivers/net/titan_ge.c
--- linux-2.4.29-pre3/drivers/net/titan_ge.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/titan_ge.c	2005-01-12 10:54:50.307666264 -0800
@@ -0,0 +1,2305 @@
+/*
+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * The MAC unit of the Titan consists of the following:
+ *
+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
+ * -> FIFO is where the incoming and outgoing data is placed
+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
+ *    the data into the FIFO for Rx
+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. 
+ * -> AFX is the address filtering block
+ * -> GMII block to communicate with the PHY
+ *
+ * Rx will look like the following:
+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
+ *
+ * Tx will look like the following:
+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
+ *
+ * The Titan driver has support for the following performance features:
+ * -> Rx side checksumming 
+ * -> Jumbo Frames
+ * -> Interrupt Coalscing
+ * -> Rx NAPI 
+ * -> SKB Recycling
+ * -> Transmit/Receive descriptors in SRAM
+ * -> Fast routing for IP forwarding
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/pci.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/prefetch.h>
+
+/* For MII specifc registers, titan_mdio.h should be included */
+#include <net/ip.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+#include "titan_ge.h"
+#include "titan_mdio.h"
+
+/* Static Function Declarations	 */
+static int titan_ge_eth_open(struct net_device *);
+static int titan_ge_eth_stop(struct net_device *);
+static int titan_ge_change_mtu(struct net_device *, int);
+static struct net_device_stats *titan_ge_get_stats(struct net_device *);
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
+				      unsigned long, unsigned long,
+				      unsigned long);
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
+				      unsigned long, unsigned long);
+
+static int titan_ge_open(struct net_device *);
+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
+static int titan_ge_stop(struct net_device *);
+static int titan_ge_set_mac_address(struct net_device *, void *);
+
+static unsigned long titan_ge_tx_coal(unsigned long, int);
+static unsigned long titan_ge_rx_coal(unsigned long, int);
+
+static void titan_ge_port_reset(unsigned int);
+static int titan_ge_free_tx_queue(titan_ge_port_info *);
+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
+
+static int titan_ge_init(int);
+static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
+
+/*
+ * Some configuration for the FIFO and the XDMA channel needs
+ * to be done only once for all the ports. This flag controls
+ * that
+ */
+unsigned long config_done = 0;
+
+/*
+ * One time out of memory flag
+ */
+unsigned int oom_flag = 0;
+
+#ifdef TITAN_RX_NAPI
+static int titan_ge_poll(struct net_device *netdev, int *budget);
+#endif
+
+int titan_ge_receive_queue(struct net_device *, unsigned int);
+
+/* MAC Address */
+extern unsigned char titan_ge_mac_addr_base[6];
+
+/* Support for Rx NAPI */
+#ifdef TITAN_RX_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);
+	mb();
+        clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+#endif
+
+/* 
+ * The Titan GE has two alignment requirements:
+ * -> skb->data to be cacheline aligned (32 byte)
+ * -> IP header alignment to 16 bytes
+ *
+ * The latter is not implemented. So, that results in an extra copy on
+ * the Rx. This is a big performance hog. For the former case, the 
+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
+ * requested is calculated:
+ * 
+ * Ethernet Frame Size : 1518
+ * Ethernet Header     : 14
+ * Future Titan change for IP header alignment : 2
+ *
+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For the future 
+ * revisions of the chip that do support IP header alignment, we will use
+ * skb_reserve().
+ */
+
+#define ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + (64UL - 1UL)) \
+	& ~(64UL - 1UL)) - (unsigned long)(addr))
+
+#define titan_ge_alloc_skb(__length, __gfp_flags) \
+({      struct sk_buff *__skb; \
+        __skb = alloc_skb((__length) + 64, (__gfp_flags)); \
+        if(__skb) { \
+                int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
+                if(__offset) \
+                        skb_reserve(__skb, __offset); \
+        } \
+        __skb; \
+})
+
+/*
+ * Configure the GMII block of the Titan based 
+ * on what the PHY tells us
+ */
+static void titan_ge_gmii_config(int port_num)
+{
+	volatile unsigned int reg_data = 0, phy_reg;
+	int err;
+
+	err = titan_ge_mdio_read(port_num,
+                               TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+
+	if (err == TITAN_GE_MDIO_ERROR) {
+                printk(KERN_ERR
+                       "Could not read PHY control register 0x11 \n");
+		printk(KERN_ERR
+			"Setting speed to 1000 Mbps and Duplex to Full \n");
+
+		return TITAN_ERROR;
+        }
+
+	err = titan_ge_mdio_write(port_num,
+			TITAN_GE_MDIO_PHY_IE, 0);
+
+	if (phy_reg & 0x8000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 1000 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + 
+					(port_num << 12)), 0x201);
+		}  else {
+			/* Half Duplex and 1000 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x2201);
+			}
+	}
+	if (phy_reg & 0x4000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 100 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x100);
+		} else {
+			/* Half Duplex and 100 Mbps */
+			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+					(port_num << 12)), 0x2100);
+		}
+	}
+	reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
+				(port_num << 12));
+	reg_data |= 0x3;
+	TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
+			(port_num << 12)), reg_data);
+}
+
+/*
+ * Enable the TMAC if it is not
+ */
+static void titan_ge_enable_tx(unsigned int port_num)
+{
+	unsigned long reg_data;
+
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12));
+	if (!(reg_data & 0x8000)) {
+		printk("TMAC disabled for port %d!! \n", port_num);
+
+		reg_data |= 0x0001;	/* Enable TMAC */
+		reg_data |= 0x4000;	/* CRC Check Enable */
+		reg_data |= 0x2000;	/* Padding enable */
+		reg_data |= 0x0800;	/* CRC Add enable */
+		reg_data |= 0x0080;	/* PAUSE frame */
+
+		TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12)), reg_data);
+	}
+}
+
+/*
+ * Tx Timeout function
+ */
+static void titan_ge_tx_timeout(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+
+	printk(KERN_INFO "%s: TX timeout  ", netdev->name);
+	printk(KERN_INFO "Resetting card \n");
+
+	/* Do the reset outside of interrupt context */
+	schedule_task(&titan_ge_eth->tx_timeout_task);
+}
+
+/*
+ * Update the AFX tables for UC and MC for slice 0 only
+ */
+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
+{
+	unsigned int i;
+	volatile unsigned long reg_data = 0;
+	u8 p_addr[6];
+	int port = titan_ge_eth->port_num;
+
+	memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
+
+	/* Set the MAC address here for TMAC and RMAC */
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
+                       ((p_addr[5] << 8) | p_addr[4]));
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
+                       ((p_addr[3] << 8) | p_addr[2]));
+        TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), 
+                       ((p_addr[1] << 8) | p_addr[0]));
+
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
+                       ((p_addr[5] << 8) | p_addr[4]));
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
+                       ((p_addr[3] << 8) | p_addr[2]));
+        TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
+                       ((p_addr[1] << 8) | p_addr[0]));
+
+	TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
+	/* Configure the eight address filters */
+	for (i = 0; i < 8; i++) {
+		/* Select each of the eight filters */
+		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
+				(port << 12)), i);
+
+		/* Configure the match */
+		reg_data = 0x9;	/* Forward Enable Bit */
+		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
+				(port << 12)), reg_data);
+
+		/* Finally, AFX Exact Match Address Registers */
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
+			       ((p_addr[1] << 8) | p_addr[0]));
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
+			       ((p_addr[3] << 8) | p_addr[2]));
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
+			       ((p_addr[5] << 8) | p_addr[4]));
+
+		/* VLAN id set to 0 */
+		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + 
+				(port << 12)), 0);
+	}
+}
+
+/*
+ * Actual Routine to reset the adapter when the timeout occurred
+ */
+static void titan_ge_tx_timeout_task(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+	int port = titan_ge_eth->port_num;
+
+	printk("Titan GE: Transmit timed out. Resetting ... \n");
+
+	/* Dump debug info */
+	printk(KERN_ERR "TRTG cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x100c + (port << 12)));
+
+	/* Fix this for the other ports */
+	printk(KERN_ERR "FIFO cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x482c));
+	printk(KERN_ERR "IE cause : %x \n",
+			(unsigned long)TITAN_GE_READ(0x0040));
+	printk(KERN_ERR "XDMA GDI ERROR : %x \n",
+			(unsigned long)TITAN_GE_READ(0x5008 + (port << 8)));
+	printk(KERN_ERR "CHANNEL ERROR: %x \n",
+			(unsigned long)TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+						+ (port << 8)));	
+
+	netif_device_detach(netdev);
+	titan_ge_port_reset(titan_ge_eth->port_num);
+	titan_ge_port_start(netdev, titan_ge_eth);
+	netif_device_attach(netdev);
+}
+
+/*
+ * Change the MTU of the Ethernet Device
+ */
+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+	unsigned long flags;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+
+	if ((new_mtu > 9500) || (new_mtu < 64)) {
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+		return -EINVAL;
+	}
+
+	netdev->mtu = new_mtu;
+
+	/* Now we have to reopen the interface so that SKBs with the new
+	 * size will be allocated */
+
+	if (netif_running(netdev)) {
+		if (titan_ge_eth_stop(netdev) != TITAN_OK) {
+			printk(KERN_ERR
+			       "%s: Fatal error on stopping device\n",
+			       netdev->name);
+			spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+			return -1;
+		}
+
+		if (titan_ge_eth_open(netdev) != TITAN_OK) {
+			printk(KERN_ERR
+			       "%s: Fatal error on opening device\n",
+			       netdev->name);
+			spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+			return -1;
+		}
+	}
+
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+	return 0;
+}
+
+/*
+ * Reset the XDMA unit due to errors
+ */
+static void titan_ge_xdma_reset(void)
+{
+       unsigned long   reg_data;
+
+       reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+       reg_data |= 0x80000000;
+       TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+
+       mdelay(2);
+
+       reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+       reg_data &= ~(0x80000000);
+       TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+}
+
+/*
+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line
+ * only. Once an interrupt is triggered, figure out the port and then check
+ * the channel.
+ */
+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id,
+	struct pt_regs *regs)
+{
+	struct net_device *netdev = (struct net_device *) dev_id;
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, reg_data;
+	unsigned long eth_int_cause_error = 0, is;
+	unsigned long eth_int_cause1;
+	int err = 0;
+#ifdef CONFIG_SMP
+	unsigned long eth_int_cause2;
+#endif
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Ack the CPU interrupt */
+	if (port_num == 1) {
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb001b00);
+		*(volatile u_int32_t *)(0xfffffffffb001b0c) = is;
+#else
+                is = *(volatile u_int32_t *)(0xfb001b00);
+                *(volatile u_int32_t *)(0xfb001b0c) = is;
+#endif
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb002b00);
+		*(volatile u_int32_t *)(0xfffffffffb002b0c) = is;
+#else
+		is = *(volatile u_int32_t *)(0xfb002b00);
+		*(volatile u_int32_t *)(0xfb002b0c) = is;
+#endif
+#endif
+        }
+
+        if (port_num == 0) {
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb001b10);
+		*(volatile u_int32_t *)(0xfffffffffb001b1c) = is;
+#else
+                is = *(volatile u_int32_t *)(0xfb001b10);
+                *(volatile u_int32_t *)(0xfb001b1c) = is;
+#endif
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS64
+		is = *(volatile u_int32_t *)(0xfffffffffb002b10);
+		*(volatile u_int32_t *)(0xfffffffffb002b1c) = is;
+#else
+		is = *(volatile u_int32_t *)(0xfb002b10);
+		*(volatile u_int32_t *)(0xfb002b1c) = is;
+#endif
+#endif
+        }
+
+	eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+#ifdef CONFIG_SMP
+	eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
+#endif
+
+	/* Spurious interrupt */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
+#else
+	if (eth_int_cause1 == 0) {
+#endif
+		eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
+					(port_num << 8));
+
+		if (eth_int_cause_error == 0)
+			return IRQ_NONE;
+	}
+
+	/* Handle Tx first. No need to ack interrupts */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 & 0x20202) || 
+		(eth_int_cause2 & 0x20202) )
+#else
+	if (eth_int_cause1 & 0x20202) 
+#endif
+		titan_ge_free_tx_queue(titan_ge_eth);
+		
+#ifdef TITAN_RX_NAPI
+	/* Handle the Rx next */
+#ifdef CONFIG_SMP
+	if ( (eth_int_cause1 & 0x10101) ||
+		(eth_int_cause2 & 0x10101)) {
+#else
+	if (eth_int_cause1 & 0x10101) {
+#endif
+		if (netif_rx_schedule_prep(netdev)) {
+			unsigned int ack;
+	
+			ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+			/* Disable Tx and Rx both */
+			if (port_num == 0) 
+				ack &= ~(0x3);
+			if (port_num == 1) 
+				ack &= ~(0x300);
+
+			if (port_num == 2)
+				ack &= ~(0x30000);
+
+			/* Interrupts have been disabled */
+			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
+
+			__netif_rx_schedule(netdev);
+		}
+	}
+#else
+	titan_ge_free_tx_queue(titan_ge_eth);
+	count = titan_ge_receive_queue(netdev, 0);
+
+#endif
+	/* Handle error interrupts */
+        if (eth_int_cause_error && 
+		(eth_int_cause_error != 0x2)) {
+		printk(KERN_ERR
+			"XDMA Channel Error : %x  on port %d\n",
+			eth_int_cause_error, port_num);
+
+		printk(KERN_ERR
+			"XDMA GDI Hardware error : %x  on port %d\n",
+			TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
+
+		printk(KERN_ERR
+			"XDMA currently has %d Rx descriptors \n",
+			TITAN_GE_READ(0x5048 + (port_num << 8)));
+
+		printk(KERN_ERR
+			"XDMA currently has prefetcted %d Rx descriptors \n",
+			TITAN_GE_READ(0x505c + (port_num << 8)));
+	
+                TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
+                               (port_num << 8)), eth_int_cause_error);
+        }
+
+	/*
+	 * PHY interrupt to inform abt the changes. Reading the 
+	 * PHY Status register will clear the interrupt
+	 */
+	if ((!(eth_int_cause1 & 0x30303)) && 
+		(eth_int_cause_error == 0)) {
+		err =
+		    titan_ge_mdio_read(port_num,
+			       TITAN_GE_MDIO_PHY_IS, &reg_data);
+
+		if (reg_data & 0x0400) {
+			/* Link status change */
+			titan_ge_mdio_read(port_num,
+				   TITAN_GE_MDIO_PHY_STATUS, &reg_data);
+			if (!(reg_data & 0x0400)) {
+				/* Link is down */
+				netif_carrier_off(netdev);
+				netif_stop_queue(netdev);
+			} else {
+				/* Link is up */
+				netif_carrier_on(netdev);
+				netif_wake_queue(netdev);
+
+				/* Enable the queue */
+				titan_ge_enable_tx(port_num);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Multicast and Promiscuous mode set. The 
+ * set_multi entry point is called whenever the 
+ * multicast address list or the network interface 
+ * flags are updated.
+ */
+static void titan_ge_set_multi(struct net_device *netdev)
+{
+	unsigned long reg_data;
+	unsigned int port_num;
+	titan_ge_port_info *titan_ge_eth;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + 
+				(port_num << 12));
+
+	if (netdev->flags & IFF_PROMISC) {
+		reg_data |= 0x2;
+	}
+	else if (netdev->flags & IFF_ALLMULTI) {
+		reg_data |= 0x01;
+		reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
+	}
+	else {
+		reg_data = 0x2;
+	}
+
+	TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + 
+			(port_num << 12)), reg_data);
+	if (reg_data & 0x01) {
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
+				(port_num << 12)), 0xffff);
+		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
+				(port_num << 12)), 0xffff);
+	}
+}
+
+/*
+ * Open the network device
+ */
+static int titan_ge_open(struct net_device *netdev)
+{
+	int retval;
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	retval = request_irq(TITAN_ETH_PORT_IRQ - port_num, titan_ge_int_handler,
+		     SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev);
+
+	if (retval != 0) {
+		printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
+		return -1;
+	} else {
+		netdev->irq = TITAN_ETH_PORT_IRQ - port_num;
+		printk(KERN_INFO "Assigned IRQ %d to port %d\n", 
+				netdev->irq, port_num);
+	}
+
+	spin_lock_irq(&(titan_ge_eth->lock));
+
+	if (titan_ge_eth_open(netdev) != TITAN_OK) {
+		printk("%s: Error opening interface \n", netdev->name);
+		spin_unlock_irq(&(titan_ge_eth->lock));
+		free_irq(netdev->irq, netdev);
+		return -EBUSY;
+	}
+
+	SET_MODULE_OWNER(netdev);
+	spin_unlock_irq(&(titan_ge_eth->lock));
+	return 0;
+}
+
+/*
+ * Return the Rx buffer back to the Rx ring
+ */
+static int titan_ge_rx_return_buff(titan_ge_port_info * titan_ge_port,
+					struct sk_buff *skb)
+{
+	int rx_used_desc;
+	volatile titan_ge_rx_desc *rx_desc;
+
+	rx_used_desc = titan_ge_port->rx_used_desc_q;
+	rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	rx_desc->buffer_addr =
+               pci_map_single(0, skb->data, TITAN_GE_JUMBO_BUFSIZE - 2,
+                                            PCI_DMA_FROMDEVICE);
+#else
+	rx_desc->buffer_addr = 
+                pci_map_single(0, skb->data, TITAN_GE_STD_BUFSIZE - 2,
+                                            PCI_DMA_FROMDEVICE);
+#endif
+
+	titan_ge_port->rx_skb[rx_used_desc] = skb;
+	rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
+
+	titan_ge_port->rx_used_desc_q =
+    	(rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
+
+	return TITAN_OK;
+}
+
+/*
+ * Allocate the SKBs for the Rx ring. Also used 
+ * for refilling the queue
+ */
+static int titan_ge_rx_task(struct net_device *netdev, 
+				titan_ge_port_info *titan_ge_eth)
+{
+	struct sk_buff *skb;
+	int count = 0;
+
+	while (titan_ge_eth->rx_ring_skbs < titan_ge_eth->rx_ring_size) {
+
+	/* First try to get the skb from the recycler */
+#ifdef TITAN_GE_JUMBO_FRAMES
+		skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
+#else	
+		skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
+#endif
+		if (!skb) {	
+			/* OOM, set the flag */
+			printk("OOM \n");
+			oom_flag = 1;
+			break;
+		}
+		count++;
+		skb->dev = netdev;
+
+		titan_ge_eth->rx_ring_skbs++;
+
+		if (titan_ge_rx_return_buff(titan_ge_eth, skb) !=
+		    TITAN_OK) {
+			printk(KERN_ERR "%s: Error allocating RX Ring\n",
+		       		netdev->name);
+			break;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * Actual init of the Tital GE port. There is one register for 
+ * the channel configuration
+ */
+static void titan_port_init(struct net_device *netdev,
+			    titan_ge_port_info * titan_ge_eth)
+{
+	unsigned long reg_data;
+	
+	titan_ge_port_reset(titan_ge_eth->port_num);
+
+	/* First reset the TMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data |= 0x80000000;
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	udelay(30);
+
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data &= ~(0xc0000000);
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	/* Now reset the RMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data |= 0x00080000;
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+	udelay(30);
+
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+	reg_data &= ~(0x000c0000);
+	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+}
+
+/*
+ * Start the port. All the hardware specific configuration
+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
+ * go here
+ */
+static int titan_ge_port_start(struct net_device *netdev,
+				titan_ge_port_info * titan_port)
+{
+	volatile unsigned long reg_data, reg_data1;
+	int count = 0;
+	int port_num = titan_port->port_num;
+	unsigned long reg_data_1;
+
+	if (config_done == 0) {
+		reg_data = TITAN_GE_READ(0x0004);
+		reg_data |= 0x100;
+		TITAN_GE_WRITE(0x0004, reg_data);
+
+		reg_data &= ~(0x100);
+		TITAN_GE_WRITE(0x0004, reg_data);
+
+		/* Turn on GMII/MII mode and turn off TBI mode */
+		reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
+        	reg_data |= 0x00000700;
+		reg_data &= ~(0x00800000); /* Fencing */
+#ifdef TITAN_RX_NAPI
+		TITAN_GE_WRITE(0x000c, 0x00001100);
+#else
+		TITAN_GE_WRITE(0x000c, 0x00000100); /* No WCIMODE */
+#endif
+	        TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
+
+		/* Set the CPU Resource Limit register */
+		TITAN_GE_WRITE(0x00f8, 0x8); 
+
+		/* Be conservative when using the BIU buffers */
+		TITAN_GE_WRITE(0x0068, 0x4);
+	}
+
+#ifdef TITAN_RX_NAPI
+	titan_port->tx_threshold = 0;
+	titan_port->rx_threshold = 0;
+#endif
+
+	/* We need to write the descriptors for Tx and Rx */
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
+                       (unsigned long) titan_port->tx_dma);
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
+                       (unsigned long) titan_port->rx_dma);
+
+	if (config_done == 0) {
+		/* Step 1:  XDMA config	*/
+	        reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+		reg_data &= ~(0x80000000);      /* clear reset */
+       		reg_data |= 0x1 << 29;	/* sparse tx descriptor spacing */
+		reg_data |= 0x1 << 28;	/* sparse rx descriptor spacing */
+		reg_data |= (0x1 << 23) | (0x1 << 24);  /* Descriptor Coherency */ 
+		reg_data |= (0x1 << 21) | (0x1 << 22);  /* Data Coherency */
+		TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+	}
+
+	/* IR register for the XDMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
+       	reg_data |= 0x80068000; /* No Rx_OOD */
+       	TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
+
+	/* Start the Tx and Rx XDMA controller */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
+	reg_data &= 0x4fffffff;     /* Clear tx reset */
+	reg_data &= 0xfff4ffff;     /* Clear rx reset */
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	reg_data |= 0xa0 | 0x30030000;
+#else
+	reg_data |= 0x40 | 0x20030000;
+#endif
+
+#ifndef CONFIG_SMP
+	reg_data &= ~(0x10);
+	reg_data |= 0x0f; /* All of the packet */
+#endif
+
+        TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
+
+	/* Rx desc count */
+	count = titan_ge_rx_task(netdev, titan_port);
+	TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
+	count = TITAN_GE_READ(0x5048 + (port_num << 8));
+
+	udelay(30);
+
+	/* 
+	 * Step 2:  Configure the SDQPF, i.e. FIFO 
+	 */
+	if (config_done == 0) {
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+		reg_data = 0x1;
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+		reg_data &= ~(0x1);
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+		reg_data = 0x1;
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+		reg_data &= ~(0x1);
+        	TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+        	TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+	}
+	/* 
+	 * Enable RX FIFO 0, 4 and 8 
+	 */
+	if (port_num == 0) {
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
+	
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10);
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+		/* 
+		 * BAV2,BAV and DAV settings for the Rx FIFO 
+		 */
+        	reg_data1 = TITAN_GE_READ(0x4844);
+	       	reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+        	TITAN_GE_WRITE(0x4844, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+
+		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+		reg_data |= (0xff << 10);
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+	
+		/* 
+		 * BAV2, BAV and DAV settings for the Tx FIFO 
+		 */
+	        reg_data1 = TITAN_GE_READ(0x4944);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+	        TITAN_GE_WRITE(0x4944, reg_data1);
+	
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+	}
+
+	if (port_num == 1) {
+		reg_data = TITAN_GE_READ(0x4870);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (0xff + 1);
+
+		TITAN_GE_WRITE(0x4870, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x4874);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x4874, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4870, reg_data);
+
+		reg_data = TITAN_GE_READ(0x494c);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x494c, reg_data);
+		reg_data |= (0xff << 10) | (0xff + 1);
+		TITAN_GE_WRITE(0x494c, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x4950);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x4950, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x494c, reg_data);
+	}
+
+	/*
+	 * Titan 1.2 revision does support port #2
+	 */
+	if (port_num == 2) {
+		/*
+		 * Put the descriptors in the SRAM
+		 */
+		reg_data = TITAN_GE_READ(0x48a0);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x48a4);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x48a4, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		
+		reg_data = TITAN_GE_READ(0x4958);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+		TITAN_GE_WRITE(0x4958, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x495c);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x495c, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+	}
+
+	if (port_num == 2) {
+		reg_data = TITAN_GE_READ(0x48a0);
+
+		reg_data |= 0x100000;
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+		/*
+		 * BAV2,BAV and DAV settings for the Rx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x48a4);
+		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+		TITAN_GE_WRITE(0x48a4, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x48a0, reg_data);
+
+		reg_data = TITAN_GE_READ(0x4958);
+		reg_data |= 0x100000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+		reg_data |= (0xff << 10) | (2*(0xff + 1));
+		TITAN_GE_WRITE(0x4958, reg_data);
+
+		/*
+		 * BAV2, BAV and DAV settings for the Tx FIFO
+		 */
+		reg_data1 = TITAN_GE_READ(0x495c);
+		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+		TITAN_GE_WRITE(0x495c, reg_data1);
+
+		reg_data &= ~(0x00100000);
+		reg_data |= 0x200000;
+
+		TITAN_GE_WRITE(0x4958, reg_data);
+	}
+
+	/* 
+	 * Step 3:  TRTG block enable 
+	 */
+	reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
+	/*
+	 * This is the 1.2 revision of the chip. It has fix for the
+	 * IP header alignment. Now, the IP header begins at an
+	 * aligned address and this wont need an extra copy in the
+	 * driver. This performance drawback existed in the previous
+	 * versions of the silicon
+	 */
+	reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
+	reg_data_1 |= 0x40000000;
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	reg_data_1 |= 0x04000000;
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	mdelay(5);
+
+	reg_data_1 &= ~(0x04000000);
+	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+	mdelay(5);
+
+	reg_data |= 0x0001; 
+	TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
+
+	/* 
+	 * Step 4:  Start the Tx activity 
+	 */
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
+#ifdef TITAN_GE_JUMBO_FRAMES
+	TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
+#endif
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
+	reg_data |= 0x0001;	/* Enable TMAC */
+	reg_data |= 0x6c70;	/* PAUSE also set */
+
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+	udelay(30);
+
+	/* Destination Address drop bit */
+        reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
+        reg_data |= 0x218;        /* DA_DROP bit and pause */
+        TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
+
+	TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+	TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
+#endif
+	/* Start the Rx activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
+	reg_data |= 0x0001;	/* RMAC Enable */
+	reg_data |= 0x0010;	/* CRC Check enable */
+	reg_data |= 0x0040;	/* Min Frame check enable */
+	reg_data |= 0x4400;	/* Max Frame check enable */
+
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+	udelay(30);
+
+	/* 
+	 * Enable the Interrupts for Tx and Rx 
+	 */
+	reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+	if (port_num == 0) {
+		reg_data1 |= 0x3;
+#ifdef CONFIG_SMP
+		TITAN_GE_WRITE(0x0038, 0x003);
+#else
+		TITAN_GE_WRITE(0x0038, 0x303);
+#endif
+	}
+
+	if (port_num == 1) {
+		reg_data1 |= 0x300;
+	}
+
+	if (port_num == 2)
+		reg_data1 |= 0x30000;
+
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
+	TITAN_GE_WRITE(0x003c, 0x300);
+	
+	if (config_done == 0) {
+		TITAN_GE_WRITE(0x0024, 0x04000024);	/* IRQ vector */
+		TITAN_GE_WRITE(0x0020, 0x000fb000);	/* INTMSG base */
+	}
+
+	/* Priority */
+	reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
+	reg_data &= ~(0x00f00000);
+	TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
+
+	/* Step 5:  GMII config */
+	titan_ge_gmii_config(port_num);
+
+	if (config_done == 0) {
+		TITAN_GE_WRITE(0x1a80, 0);
+		config_done = 1;
+	}
+
+	return TITAN_OK;
+}
+
+/*
+ * Function to queue the packet for the Ethernet device
+ */
+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
+				struct sk_buff * skb)
+{
+	volatile titan_ge_tx_desc *tx_curr;
+	int port_num = titan_ge_eth->port_num;
+	unsigned int curr_desc =
+			titan_ge_eth->tx_curr_desc_q;
+
+	tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
+	tx_curr->buffer_addr = 
+		pci_map_single(0, skb->data, skb->len - skb->data_len,
+					PCI_DMA_TODEVICE);
+
+	titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
+	tx_curr->buffer_len = skb->len - skb->data_len;
+
+	/* Last descriptor enables interrupt and changes ownership */
+	tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
+
+	/* Kick the XDMA to start the transfer from memory to the FIFO */
+        TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
+
+	/* Current descriptor updated */
+	titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
+
+	/* Prefetch the next descriptor */
+#ifdef CONFIG_CPU_HAS_PREFETCH
+	rm9000_prefetch(&(titan_ge_eth->tx_desc_area[
+				titan_ge_eth->tx_curr_desc_q]));
+#endif
+}
+
+/*
+ * Actually does the open of the Ethernet device
+ */
+static int titan_ge_eth_open(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, size, phy_reg;
+	unsigned long reg_data;
+	int err = 0;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Rx activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	/* Clear the port interrupts */
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
+			(port_num << 8)), 0x0);
+
+	if (config_done == 0) {
+		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
+		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
+	}
+
+	/* Set the MAC Address */
+	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+	
+	if (config_done == 0)
+		titan_port_init(netdev, titan_ge_eth);
+
+	titan_ge_update_afx(titan_ge_eth);
+
+	/* Allocate the Tx ring now */
+	titan_ge_eth->tx_ring_skbs = 0;
+	titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
+	size = titan_ge_eth->tx_ring_size * sizeof(titan_ge_tx_desc);
+
+	/* Allocate space in the SRAM for the descriptors */
+        if (port_num == 0) {
+                titan_ge_eth->tx_desc_area =
+                    (titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL);
+
+                titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL);
+        }
+
+	if (port_num == 1) {
+		titan_ge_eth->tx_desc_area =
+		    (titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL + 0x100);
+		
+		titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x100);
+	}
+
+	if (!titan_ge_eth->tx_desc_area) {
+		printk(KERN_ERR
+		       "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n",
+		       netdev->name, size, port_num);
+		return -ENOMEM;
+	}
+
+	memset((void *) titan_ge_eth->tx_desc_area, 0,
+	       titan_ge_eth->tx_desc_area_size);
+
+	/* Now initialize the Tx descriptor ring */
+	titan_ge_init_tx_desc_ring(titan_ge_eth,
+				   titan_ge_eth->tx_ring_size,
+				   (unsigned long) titan_ge_eth->
+				   tx_desc_area,
+				   (unsigned long) titan_ge_eth->tx_dma);
+
+	/* Allocate the Rx ring now */
+	titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
+	titan_ge_eth->rx_ring_skbs = 0;
+	size = titan_ge_eth->rx_ring_size * sizeof(titan_ge_rx_desc);
+
+	if (port_num == 0) {
+		titan_ge_eth->rx_desc_area =
+			(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x1000);
+
+		titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x1000);
+	}
+
+	if (port_num == 1) {
+		titan_ge_eth->rx_desc_area =
+			(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x1100);
+		titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x1100);
+	}
+
+	if (!titan_ge_eth->rx_desc_area) {
+		printk(KERN_ERR
+		       "%s: Cannot allocate Rx Ring (size %d bytes)\n",
+		       netdev->name, size);
+
+		printk(KERN_ERR
+		       "%s: Freeing previously allocated TX queues...",
+		       netdev->name);
+
+		pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
+				    (void *) titan_ge_eth->tx_desc_area,
+				    titan_ge_eth->tx_dma);
+
+		return -ENOMEM;
+	}
+
+	memset((void *) titan_ge_eth->rx_desc_area, 0,
+	       titan_ge_eth->tx_desc_area_size);
+
+	/* Now initialize the Rx ring */
+#ifdef TITAN_GE_JUMBO_FRAMES
+	if ((titan_ge_init_rx_desc_ring
+	    (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
+	     (unsigned long) titan_ge_eth->rx_desc_area, 0,
+	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#else
+	if ((titan_ge_init_rx_desc_ring
+	     (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
+	      (unsigned long) titan_ge_eth->rx_desc_area, 0,
+	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#endif
+		panic("%s: Error initializing RX Ring\n", netdev->name);
+
+	/* Fill the Rx ring with the SKBs */
+	titan_ge_port_start(netdev, titan_ge_eth);
+
+	/* 
+	 * Check if Interrupt Coalscing needs to be turned on. The
+	 * values specified in the register is multiplied by 
+	 * (8 x 64 nanoseconds) to determine when an interrupt should
+	 * be sent to the CPU. 
+	 */
+#ifndef TITAN_RX_NAPI
+	/* 
+	 * If NAPI is turned on, we disable Rx interrupts
+	 * completely. So, we dont need coalescing then. Tx side
+	 * coalescing set to very high value. Maybe, disable
+	 * Tx side interrupts completely
+	 */
+	if (TITAN_GE_RX_COAL) {
+		titan_ge_eth->rx_int_coal =
+		    titan_ge_rx_coal(TITAN_GE_RX_COAL, port_num);
+	} 
+
+#endif
+	if (TITAN_GE_TX_COAL) {
+		titan_ge_eth->tx_int_coal =
+		    titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
+	}
+
+	err =
+	    titan_ge_mdio_read(port_num,
+			       TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+	if (err == TITAN_GE_MDIO_ERROR) {
+		printk(KERN_ERR
+		       "Could not read PHY control register 0x11 \n");
+		return TITAN_ERROR;
+	}
+	if (!(phy_reg & 0x0400)) {
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+		return TITAN_ERROR;
+	} else {
+		netif_carrier_on(netdev);
+		netif_start_queue(netdev);
+	}
+
+	return TITAN_OK;
+}
+
+/*
+ * Queue the packet for Tx. Currently no support for zero copy, 
+ * checksum offload and Scatter Gather. The chip does support 
+ * Scatter Gather only. But, that wont help here since zero copy 
+ * requires support for Tx checksumming also. 
+ */
+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned long flags;
+	struct net_device_stats *stats;
+	titan_ge_eth = netdev->priv;
+
+	stats = &titan_ge_eth->stats;
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
+	    (skb_shinfo(skb)->nr_frags + 1)) {
+		netif_stop_queue(netdev);
+#ifdef CONFIG_SMP
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+		local_irq_restore(flags);
+#endif
+		printk(KERN_ERR "Tx OOD \n");
+		return 1;
+	}
+
+	titan_ge_tx_queue(titan_ge_eth, skb);
+	titan_ge_eth->tx_ring_skbs++;
+
+	if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
+#ifdef CONFIG_SMP
+		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+		local_irq_restore(flags);
+#endif
+		titan_ge_free_tx_queue(titan_ge_eth);
+#ifdef CONFIG_SMP
+		spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+		local_irq_save(flags);
+#endif
+	}
+
+	stats->tx_bytes += skb->len;
+	stats->tx_packets++;
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	netdev->trans_start = jiffies;
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+/*
+ * Fast forward function for the fast routing. Helps
+ * in IP forwarding. No semi fast forward since we
+ * have to do that extra copy on the Rx for the IP
+ * header alignment
+ */
+static int titan_ge_fast_forward(struct net_device *dev, 
+			struct sk_buff *skb, int len)
+{
+	titan_ge_port_info *titan_ge_eth = 
+			(titan_ge_port_info *)dev->priv;
+	struct ethhdr *eth = (void*)skb->data;
+
+	if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+		struct rtable *rt;
+		struct iphdr *iph;
+		unsigned h;
+
+		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 &&
+			((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 == 0) {
+				struct net_device *odev = rt->u.dst.dev;
+
+				if (*(u8*)iph != 0x45 ||
+					(eth->h_dest[0]&1) ||
+					!neigh_is_valid(rt->u.dst.neighbour) ||
+					iph->ttl <= 1) {
+						return 1;		
+				}
+				ip_decrease_ttl(iph);
+				skb_put(skb, len);
+
+				memcpy(eth->h_source, odev->dev_addr, 6);
+				memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
+				skb->dev = odev;
+				skb->pkt_type = PACKET_FASTROUTE;
+
+				if (netif_running(odev) &&
+				   (spin_trylock(&odev->xmit_lock))) {
+					if(odev->xmit_lock_owner != 0) {
+						odev->xmit_lock_owner=0;
+					}
+					if (odev->hard_start_xmit(skb,odev) == 0) {
+						odev->xmit_lock_owner=-1;
+						spin_unlock(&odev->xmit_lock);
+						return 0;
+					} 
+				}
+				skb->nh.raw = skb->data + ETH_HLEN;
+				skb->protocol = __constant_htons(ETH_P_IP);
+				return 1;
+			}
+	}
+	return 1;
+}
+
+#endif
+
+/*
+ * Actually does the Rx. Rx side checksumming supported.
+ */
+static int titan_ge_rx(struct net_device *netdev, int port_num,
+			titan_ge_port_info * titan_ge_port,
+		       titan_ge_packet * packet)
+{
+	int rx_curr_desc, rx_used_desc;
+	volatile titan_ge_rx_desc *rx_desc;
+
+	rx_curr_desc = titan_ge_port->rx_curr_desc_q;
+	rx_used_desc = titan_ge_port->rx_used_desc_q;
+
+	if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) 
+		return TITAN_ERROR;
+
+	rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
+
+	if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) 
+		return TITAN_ERROR;
+
+	packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
+	packet->len = (rx_desc->cmd_sts & 0x7fff);
+
+	/* 
+	 * At this point, we dont know if the checksumming 
+	 * actually helps relieve CPU. So, keep it for 
+	 * port 0 only
+	 */
+	packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
+
+	titan_ge_port->rx_curr_desc_q =
+	    (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
+	
+	/* Prefetch the next descriptor */
+#ifdef CONFIG_CPU_HAS_PREFETCH
+	rm9000_prefetch(&(titan_ge_port->rx_desc_area[
+			titan_ge_port->rx_curr_desc_q + 1]));
+#endif
+
+	return TITAN_OK;
+}
+
+/*
+ * Free the Tx queue of the used SKBs
+ */
+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
+{
+	unsigned long flags;
+
+	/* Take the lock */
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&(titan_ge_eth->lock), flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) 
+		if (titan_ge_eth->tx_ring_skbs != 1)
+			titan_ge_eth->tx_ring_skbs--;
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	return TITAN_OK;
+}
+
+/*
+ * Threshold beyond which we do the cleaning of
+ * Tx queue and new allocation for the Rx 
+ * queue
+ */
+#define	TX_THRESHOLD	4
+#define	RX_THRESHOLD	10
+
+/*
+ * Receive the packets and send it to the kernel. 
+ */
+int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+	titan_ge_packet packet;
+	struct net_device_stats *stats;
+	struct sk_buff *skb;
+	unsigned long received_packets = 0;
+	unsigned int ack;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+	stats = &titan_ge_eth->stats;
+
+	while ((--max)
+	       && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
+
+		titan_ge_eth->rx_ring_skbs--;
+
+#ifdef TITAN_RX_NAPI
+		if (--titan_ge_eth->rx_work_limit < 0)
+			break;
+		received_packets++;
+#endif
+		stats->rx_packets++;
+		stats->rx_bytes += packet.len;
+
+		if ((packet.cmd_sts & TITAN_GE_RX_PERR) ||
+			(packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) ||
+			(packet.cmd_sts & TITAN_GE_RX_TRUNC) ||
+			(packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) {
+				stats->rx_dropped++;
+				dev_kfree_skb_any(skb);
+	
+				continue;
+		}
+		/* 
+		 * Either support fast path or slow path. Decision
+		 * making can really slow down the performance. The
+		 * idea is to cut down the number of checks and improve
+		 * the fastpath.
+		 */
+#ifdef CONFIG_NET_FASTROUTE
+		switch (titan_ge_fast_forward(netdev, 
+				packet.skb, packet.len)) {
+			case 0:
+				goto gone;
+			case 1:
+				break;
+		}
+#endif
+		skb = (struct sk_buff *) packet.skb;
+		/*
+		 * This chip is wierd. Does not have a byte level offset
+		 * to fix the IP header alignment issue. Now, do an extra
+		 * copy only if the custom pattern is not present
+		 */
+		skb_put(skb, packet.len - 2);
+
+		/*
+		 * Increment data pointer by two since thats where
+		 * the MAC starts
+		 */
+		skb_reserve(skb, 2);
+		skb->protocol = eth_type_trans(skb, netdev);
+		netif_receive_skb(skb);
+
+#ifdef CONFIG_NET_FASTROUTE
+gone:
+#endif
+
+#ifdef TITAN_RX_NAPI
+		if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
+			ack = titan_ge_rx_task(netdev, titan_ge_eth);
+        	        TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
+			titan_ge_eth->rx_threshold = 0;
+		} else
+			titan_ge_eth->rx_threshold++;
+#else
+		ack = titan_ge_rx_task(netdev, titan_ge_eth);
+		TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
+#endif
+
+#ifdef TITAN_RX_NAPI
+		if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
+			titan_ge_eth->tx_threshold = 0;
+			titan_ge_free_tx_queue(titan_ge_eth);
+		}
+		else
+			titan_ge_eth->tx_threshold++;
+#endif
+
+	}
+	return received_packets;
+}
+
+
+#ifdef TITAN_RX_NAPI
+
+/*
+ * Enable the Rx side interrupts 
+ */
+static void titan_ge_enable_int(unsigned int port_num,
+			titan_ge_port_info *titan_ge_eth,
+			struct net_device *netdev)
+{
+	unsigned long reg_data = 
+		TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+	if (port_num == 0)
+		reg_data |= 0x3;
+	if (port_num == 1)
+		reg_data |= 0x300;
+	if (port_num == 2)
+		reg_data |= 0x30000;
+
+	/* Re-enable interrupts */
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
+}
+
+/*
+ * Main function to handle the polling for Rx side NAPI.
+ * Receive interrupts have been disabled at this point. 
+ * The poll schedules the transmit followed by receive.
+ */	
+static int titan_ge_poll(struct net_device *netdev, int *budget)
+{
+        titan_ge_port_info *titan_ge_eth = netdev->priv;
+        int port_num = titan_ge_eth->port_num; 
+	int work_done = 0; 
+	unsigned long flags, status;
+
+	titan_ge_eth->rx_work_limit = *budget;
+        if (titan_ge_eth->rx_work_limit > netdev->quota)
+                titan_ge_eth->rx_work_limit = netdev->quota;
+
+	do {
+		/* Do the transmit cleaning work here */
+		titan_ge_free_tx_queue(titan_ge_eth);
+
+		/* Ack the Rx interrupts */
+		if (port_num == 0) 
+			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
+                if (port_num == 1)
+                        TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
+                if (port_num == 2)
+                        TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
+
+	        work_done += titan_ge_receive_queue(netdev, 0);
+
+		/* Out of quota and there is work to be done */	
+		if (titan_ge_eth->rx_work_limit < 0)
+			goto not_done;			
+
+		/* Receive alloc_skb could lead to OOM */	
+		if (oom_flag == 1) {
+			oom_flag = 0;
+			goto oom;
+		}
+
+		status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+	} while (status & 0x30300);
+
+	/* If we are here, then no more interrupts to process */
+	goto done;
+
+not_done:
+	*budget -= work_done;
+	netdev->quota -= work_done;
+	return 1;
+
+oom:
+	printk(KERN_ERR "OOM \n");
+	netif_rx_complete(netdev);
+	return 0;
+
+done:
+	/*
+	 * No more packets on the poll list. Turn the interrupts 
+	 * back on and we should be able to catch the new
+	 * packets in the interrupt handler
+	 */
+	if (!work_done)
+		work_done = 1;
+
+	*budget -= work_done;
+        netdev->quota -= work_done;
+
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&titan_ge_eth->lock, flags);
+#else
+	local_irq_save(flags);
+#endif
+
+	/* Remove us from the poll list */
+	netif_rx_complete(netdev);
+
+	/* Re-enable interrupts */
+	titan_ge_enable_int(port_num, titan_ge_eth, netdev);
+
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+#else
+	local_irq_restore(flags);
+#endif
+
+	return 0;
+}
+#endif
+
+/*
+ * Close the network device
+ */
+int titan_ge_stop(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	spin_lock_irq(&(titan_ge_eth->lock));
+	titan_ge_eth_stop(netdev);
+	free_irq(netdev->irq, netdev);
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irq(&titan_ge_eth->lock);
+
+	return TITAN_OK;
+}
+
+/*
+ * Free the Tx ring
+ */
+static void titan_ge_free_tx_rings(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, curr;
+	unsigned long reg_data;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Tx DMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
+				(port_num << 8));
+	reg_data |= 0xc0000000;
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+			(port_num << 8)), reg_data);
+
+	/* Disable the TMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	for (curr = 0;
+	     (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
+	     curr++) {
+		if (titan_ge_eth->tx_skb[curr]) {
+			dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
+			titan_ge_eth->tx_ring_skbs--;
+		}
+	}
+
+	if (titan_ge_eth->tx_ring_skbs != 0)
+		printk
+		    ("%s: Error on Tx descriptor free - could not free %d"
+		     " descriptors\n", netdev->name,
+		     titan_ge_eth->tx_ring_skbs);
+
+	pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
+			    (void *) titan_ge_eth->tx_desc_area,
+			    titan_ge_eth->tx_dma);
+}
+
+/*
+ * Free the Rx ring
+ */
+static void titan_ge_free_rx_rings(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num, curr;
+	unsigned long reg_data;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	/* Stop the Rx DMA */
+	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + 
+				(port_num << 8));
+	reg_data |= 0x000c0000;
+	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+			(port_num << 8)), reg_data);
+
+	/* Disable the RMAC */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+				(port_num << 12));
+	reg_data &= ~(0x00000001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+			(port_num << 12)), reg_data);
+
+	for (curr = 0;
+	     titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
+	     curr++) {
+		if (titan_ge_eth->rx_skb[curr]) {
+			dev_kfree_skb(titan_ge_eth->rx_skb[curr]);
+			titan_ge_eth->rx_ring_skbs--;
+		}
+	}
+
+	if (titan_ge_eth->rx_ring_skbs != 0)
+		printk(KERN_ERR
+		       "%s: Error in freeing Rx Ring. %d skb's still"
+		       " stuck in RX Ring - ignoring them\n", netdev->name,
+		       titan_ge_eth->rx_ring_skbs);
+
+	pci_free_consistent(0, titan_ge_eth->rx_desc_area_size,
+			    (void *) titan_ge_eth->rx_desc_area,
+			    titan_ge_eth->rx_dma);
+}
+
+/*
+ * Actually does the stop of the Ethernet device
+ */
+static int titan_ge_eth_stop(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	netif_stop_queue(netdev);
+
+	titan_ge_port_reset(titan_ge_eth->port_num);
+
+	titan_ge_free_tx_rings(netdev);
+	titan_ge_free_rx_rings(netdev);
+
+	/* Disable the Tx and Rx Interrupts for all channels */
+	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0);
+
+	return TITAN_OK;
+}
+
+/*
+ * Update the MAC address. Note that we have to write the 
+ * address in three station registers, 16 bits each. And this 
+ * has to be done for TMAC and RMAC
+ */
+static void titan_ge_update_mac_address(struct net_device *netdev)
+{
+	titan_ge_port_info *titan_ge_eth = netdev->priv;
+	unsigned int port_num = titan_ge_eth->port_num;
+	u8 p_addr[6];
+
+	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+	memcpy(p_addr, netdev->dev_addr, 6);
+
+	/* Update the Address Filtering Match tables */
+	titan_ge_update_afx(titan_ge_eth);
+
+	printk("Station MAC : %d %d %d %d %d %d  \n", 
+		p_addr[5], p_addr[4], p_addr[3], 
+		p_addr[2], p_addr[1], p_addr[0]);
+
+	/* Set the MAC address here for TMAC and RMAC */
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	return;
+}
+
+/*
+ * Set the MAC address of the Ethernet device
+ */
+int titan_ge_set_mac_address(struct net_device *netdev, void *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		netdev->dev_addr[i] = ((unsigned char *) addr)[i + 2];
+
+	titan_ge_update_mac_address(netdev);
+	return 0;
+}
+
+/*
+ * Get the Ethernet device stats
+ */
+static struct net_device_stats *titan_ge_get_stats(struct net_device
+						   *netdev)
+{
+	titan_ge_port_info *titan_ge_eth;
+	unsigned int port_num;
+
+	titan_ge_eth = netdev->priv;
+	port_num = titan_ge_eth->port_num;
+
+	return &titan_ge_eth->stats;
+}
+
+/*
+ * Register the Titan GE with the kernel
+ */
+static int __init titan_ge_init_module(void)
+{
+	unsigned long version, device;
+
+	printk(KERN_NOTICE
+	       "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
+	device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
+	version = (device & 0x000f0000) >> 16;
+	device &= 0x0000ffff;
+
+	printk(KERN_NOTICE "Device Id : %x,  Version : %x \n", device,
+	       version);
+
+	/* Register only one port */ 
+	if (titan_ge_init(0)) 
+		printk(KERN_ERR
+		       "Error registering the TITAN Ethernet driver"
+			"for port 0 \n");
+	
+	if (titan_ge_init(1)) 
+		printk(KERN_ERR "Error registering the TITAN Ethernet" 
+				"driver for port 1\n");
+
+	return 0;
+}
+
+/*
+ * Unregister the Titan GE from the kernel
+ */
+static void __init titan_ge_cleanup_module(void)
+{
+	/* Nothing to do here */
+}
+
+module_init(titan_ge_init_module);
+module_exit(titan_ge_cleanup_module);
+
+/*
+ * Initialize the Rx descriptor ring for the Titan Ge
+ */
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
+				      int rx_desc_num,
+				      int rx_buff_size,
+				      unsigned long rx_desc_base_addr,
+				      unsigned long rx_buff_base_addr,
+				      unsigned long rx_dma)
+{
+	volatile titan_ge_rx_desc *rx_desc;
+	unsigned long buffer_addr;
+	int index;
+	unsigned long titan_ge_rx_desc_bus = rx_dma;
+
+	buffer_addr = rx_buff_base_addr;
+	rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
+
+	/* Check alignment */
+	if (rx_buff_base_addr & 0xF)
+		return 0;
+
+	/* Check Rx buffer size */
+	if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
+		return 0;
+
+	/* 64-bit alignment 
+	if ((rx_buff_base_addr + rx_buff_size) & 0x7)
+		return 0; */
+
+	/* Initialize the Rx desc ring */
+	for (index = 0; index < rx_desc_num; index++) {
+		titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
+		rx_desc[index].cmd_sts = 0;
+		rx_desc[index].buffer_addr = buffer_addr;
+		titan_eth_port->rx_skb[index] = NULL;
+		buffer_addr += rx_buff_size;
+	}
+
+	titan_eth_port->rx_curr_desc_q = 0;
+	titan_eth_port->rx_used_desc_q = 0;
+
+	titan_eth_port->rx_desc_area =
+	    (titan_ge_rx_desc *) rx_desc_base_addr;
+	titan_eth_port->rx_desc_area_size =
+	    rx_desc_num * sizeof(titan_ge_rx_desc);
+	
+	titan_eth_port->rx_dma = rx_dma;
+
+	return TITAN_OK;
+}
+
+/*
+ * Initialize the Tx descriptor ring. Descriptors in the SRAM
+ */
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
+				      int tx_desc_num,
+				      unsigned long tx_desc_base_addr,
+				      unsigned long tx_dma)
+{
+	titan_ge_tx_desc *tx_desc;
+	int index;
+	unsigned long titan_ge_tx_desc_bus = tx_dma;
+
+	if (tx_desc_base_addr & 0xF)
+		return 0;
+
+	tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
+
+	for (index = 0; index < tx_desc_num; index++) {
+		titan_ge_port->tx_dma_array[index] =
+		    (dma_addr_t) titan_ge_tx_desc_bus;
+		titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
+		tx_desc[index].cmd_sts = 0x0000;
+		tx_desc[index].buffer_len = 0;
+		tx_desc[index].buffer_addr = 0x00000000;
+		titan_ge_port->tx_skb[index] = NULL;
+	}
+
+	titan_ge_port->tx_curr_desc_q = 0;
+	titan_ge_port->tx_used_desc_q = 0;
+
+	titan_ge_port->tx_desc_area =
+	    (titan_ge_tx_desc *) tx_desc_base_addr;
+	titan_ge_port->tx_desc_area_size =
+	    tx_desc_num * sizeof(titan_ge_tx_desc);
+
+	titan_ge_port->tx_dma = tx_dma;
+	return TITAN_OK;
+}
+
+/*
+ * Initialize the device as an Ethernet device
+ */
+static int titan_ge_init(int port)
+{
+	titan_ge_port_info *titan_ge_eth;
+	struct net_device *netdev;
+	int err;
+
+	netdev = alloc_etherdev(sizeof(titan_ge_port_info));
+	if (!netdev) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	netdev->open = titan_ge_open;
+	netdev->stop = titan_ge_stop;
+	netdev->hard_start_xmit = titan_ge_start_xmit;
+	netdev->get_stats = titan_ge_get_stats;
+	netdev->set_multicast_list = titan_ge_set_multi;
+	netdev->set_mac_address = titan_ge_set_mac_address;
+
+	/* Tx timeout */
+	netdev->tx_timeout = titan_ge_tx_timeout;
+	netdev->watchdog_timeo = 2 * HZ;
+
+#ifdef TITAN_RX_NAPI
+	/* Set these to very high values */
+	netdev->poll = titan_ge_poll;
+	netdev->weight = 64;
+#endif
+	netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
+	netif_carrier_off(netdev);
+	netdev->base_addr = 0;
+
+#ifdef CONFIG_NET_FASTROUTE
+	netdev->accept_fastpath = titan_accept_fastpath;
+#endif
+
+	netdev->change_mtu = titan_ge_change_mtu;
+
+	titan_ge_eth = netdev->priv;
+	/* Allocation of memory for the driver structures */
+
+	titan_ge_eth->port_num = port;
+
+	memset(&titan_ge_eth->stats, 0, sizeof(struct net_device_stats));
+
+	/* Configure the Tx timeout handler */
+	INIT_TQUEUE(&titan_ge_eth->tx_timeout_task,
+		    (void (*)(void *)) titan_ge_tx_timeout_task, netdev);
+
+	spin_lock_init(&titan_ge_eth->lock);
+
+	/* set MAC addresses */
+	memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
+	netdev->dev_addr[5] += port;
+
+	err = register_netdev(netdev);
+
+        if (err)
+                goto out_free_private;
+
+	printk(KERN_NOTICE
+	       "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       netdev->name, port, netdev->dev_addr[0],
+	       netdev->dev_addr[1], netdev->dev_addr[2],
+	       netdev->dev_addr[3], netdev->dev_addr[4],
+	       netdev->dev_addr[5]);
+
+#ifdef TITAN_RX_NAPI
+	printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
+#else
+	printk(KERN_NOTICE "Rx and Tx Coalescing ON \n");
+#endif
+
+	/*
+	 * Titan 1.2 does support port #2
+	 */
+	if (titan_ge_init(2))
+		printk(KERN_ERR "Error registering the TITAN Ethernet"
+				"driver for port 2\n");
+
+	return 0;
+
+out_free_private:
+
+out_free_netdev:
+	kfree(netdev);
+
+out:
+	return err;
+}
+
+/*
+ * Reset the Ethernet port
+ */
+static void titan_ge_port_reset(unsigned int port_num)
+{
+	unsigned int reg_data;
+
+	/* Stop the Tx port activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + 
+				(port_num << 12));
+	reg_data &= ~(0x0001);
+	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + 
+			(port_num << 12)), reg_data);
+
+	/* Stop the Rx port activity */
+	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + 
+				(port_num << 12));
+	reg_data &= ~(0x0001);
+	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + 
+			(port_num << 12)), reg_data);
+
+	return;
+}
+
+/*
+ * Return the Tx desc after use by the XDMA
+ */
+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
+{
+	int tx_desc_used;
+	struct sk_buff *skb;
+
+	tx_desc_used = titan_ge_eth->tx_used_desc_q;
+
+	/* return right away */
+	if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
+		return TITAN_ERROR;
+
+	/* Now the critical stuff */
+	skb = titan_ge_eth->tx_skb[tx_desc_used];
+
+	dev_kfree_skb_any(skb);
+
+	titan_ge_eth->tx_skb[tx_desc_used] = NULL;
+	titan_ge_eth->tx_used_desc_q =
+	    (tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
+
+	return 0;
+}
+
+#ifndef TITAN_RX_NAPI
+/*
+ * Coalescing for the Rx path
+ */
+static unsigned long titan_ge_rx_coal(unsigned long delay, int port)
+{
+	TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
+	TITAN_GE_WRITE(0x5038, delay);
+
+	return delay;
+}
+#endif
+
+/*
+ * Coalescing for the Tx path
+ */
+static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
+{
+	unsigned long rx_delay;
+
+	rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
+	delay = (delay << 16) | rx_delay;
+
+	TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
+	TITAN_GE_WRITE(0x5038, delay);
+
+	return delay;
+}
diff -urN linux-2.4.29-pre3/drivers/net/titan_ge.h linux-2.4.29-rc1/drivers/net/titan_ge.h
--- linux-2.4.29-pre3/drivers/net/titan_ge.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/titan_ge.h	2005-01-12 10:54:50.308666307 -0800
@@ -0,0 +1,436 @@
+#ifndef _TITAN_GE_H_
+#define _TITAN_GE_H_
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <asm/addrspace.h> /* For KSEG1ADDR() */
+
+/*
+ * These functions should be later moved to a more generic location since there
+ * will be others accessing it also
+ */
+
+/* 
+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in
+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 
+ * register.
+ */
+
+#ifdef CONFIG_MIPS64
+#define	TITAN_GE_BASE	0xfffffffffe000000
+#else
+#define	TITAN_GE_BASE	0xfe000000
+#endif
+
+#define	TITAN_GE_WRITE(offset, data) \
+		*(volatile u32 *)(TITAN_GE_BASE + offset) = data	
+
+#define TITAN_GE_READ(offset) *(volatile u32 *)(TITAN_GE_BASE + offset)
+
+#ifndef msec_delay
+#define msec_delay(x)   do { if(in_interrupt()) { \
+                                /* Don't mdelay in interrupt context! */ \
+                                BUG(); \
+                        } else { \
+                                set_current_state(TASK_UNINTERRUPTIBLE); \
+                                schedule_timeout((x * HZ)/1000); \
+                        } } while(0)
+#endif
+
+#define TITAN_GE_PORT_0
+
+#define	TITAN_GE_SRAM_BASE_VIRTUAL	0xf4000000
+#define	TITAN_GE_SRAM_BASE_PHYSICAL	0xf4000000
+
+#ifdef CONFIG_NET_FASTROUTE
+
+#include <linux/if_arp.h>
+#include <net/ip.h>
+
+static int titan_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;
+
+	return 0;
+}
+#endif
+
+
+/*
+ * We may need these constants
+ */
+#define TITAN_BIT0    0x00000001
+#define TITAN_BIT1    0x00000002
+#define TITAN_BIT2    0x00000004
+#define TITAN_BIT3    0x00000008
+#define TITAN_BIT4    0x00000010
+#define TITAN_BIT5    0x00000020
+#define TITAN_BIT6    0x00000040
+#define TITAN_BIT7    0x00000080
+#define TITAN_BIT8    0x00000100
+#define TITAN_BIT9    0x00000200
+#define TITAN_BIT10   0x00000400
+#define TITAN_BIT11   0x00000800
+#define TITAN_BIT12   0x00001000
+#define TITAN_BIT13   0x00002000
+#define TITAN_BIT14   0x00004000
+#define TITAN_BIT15   0x00008000
+#define TITAN_BIT16   0x00010000
+#define TITAN_BIT17   0x00020000
+#define TITAN_BIT18   0x00040000
+#define TITAN_BIT19   0x00080000
+#define TITAN_BIT20   0x00100000
+#define TITAN_BIT21   0x00200000
+#define TITAN_BIT22   0x00400000
+#define TITAN_BIT23   0x00800000
+#define TITAN_BIT24   0x01000000
+#define TITAN_BIT25   0x02000000
+#define TITAN_BIT26   0x04000000
+#define TITAN_BIT27   0x08000000
+#define TITAN_BIT28   0x10000000
+#define TITAN_BIT29   0x20000000
+#define TITAN_BIT30   0x40000000
+#define TITAN_BIT31   0x80000000
+
+/* Flow Control */
+#define	TITAN_GE_FC_NONE	0x0
+#define	TITAN_GE_FC_FULL	0x1
+#define	TITAN_GE_FC_TX_PAUSE	0x2
+#define	TITAN_GE_FC_RX_PAUSE	0x3
+
+/* Duplex Settings */
+#define	TITAN_GE_FULL_DUPLEX	0x1
+#define	TITAN_GE_HALF_DUPLEX	0x2
+
+/* Speed settings */
+#define	TITAN_GE_SPEED_1000	0x1
+#define	TITAN_GE_SPEED_100	0x2
+#define	TITAN_GE_SPEED_10	0x3
+
+/* Debugging info only */
+#undef TITAN_DEBUG
+
+/* Support for Rx side NAPI */
+#define TITAN_RX_NAPI
+
+#ifdef CONFIG_MIPS64
+#define	TITAN_GE_IE_MASK	0xfffffffffb001b64
+#define	TITAN_GE_IE_STATUS	0xfffffffffb001b60
+#else
+#define	TITAN_GE_IE_MASK	0xfb001b64
+#define	TITAN_GE_IE_STATUS	0xfb001b60
+#endif
+
+/* Support for Jumbo Frames */
+#undef TITAN_GE_JUMBO_FRAMES
+
+/* Rx buffer size */
+#ifdef TITAN_GE_JUMBO_FRAMES
+#define	TITAN_GE_JUMBO_BUFSIZE	9080
+#else
+#define	TITAN_GE_STD_BUFSIZE	1580
+#endif
+
+/* Default Tx Queue Size */
+#define	TITAN_GE_TX_QUEUE	128
+
+/* Default Rx Queue Size */
+#define	TITAN_GE_RX_QUEUE	64
+
+/* 
+ * Tx and Rx Interrupt Coalescing parameter. These values are 
+ * for 1 Ghz processor. Rx coalescing can be taken care of
+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
+ * is not adaptive. Hence, these values need to be adjusted
+ * based on load, CPU speed etc.
+ */
+#define	TITAN_GE_RX_COAL	150
+#define	TITAN_GE_TX_COAL	300
+
+#if defined(__BIG_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct _eth_rx_desc {
+        u32     reserved;	/* Unused 		*/
+        u32     buffer_addr;	/* CPU buffer address 	*/
+	u32	cmd_sts;	/* Command and Status	*/
+	u32	buffer;		/* XDMA buffer address	*/
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct _eth_tx_desc {
+        u16     cmd_sts;	/* Command, Status and Buffer count */
+	u16	buffer_len;	/* Length of the buffer	*/
+        u32     buffer_addr;	/* Physical address of the buffer */
+} titan_ge_tx_desc;
+
+#elif defined(__LITTLE_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct _eth_rx_desc {
+	u32	buffer_addr;	/* Buffer address inclusive of checksum */
+        u32     cmd_sts;	/* Command and Status info */
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct _eth_tx_desc {
+	u32     buffer_addr;	/* Physical address of the buffer */
+	u16     buffer_len;     /* Length of the buffer */
+	u16     cmd_sts;        /* Command, Status and Buffer count */
+} titan_ge_tx_desc;
+#else
+#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
+#endif
+
+/* Packet Structure */
+typedef struct _pkt_info {
+        unsigned int           len;
+        unsigned int            cmd_sts;
+        unsigned int            buffer;
+        struct sk_buff          *skb;
+	unsigned int		checksum;
+} titan_ge_packet;
+
+
+#define	PHYS_CNT	2
+
+/* Titan Port specific data structure */
+typedef struct _eth_port_ctrl {
+	unsigned int		port_num;
+	u8			port_mac_addr[6];
+
+	/* Rx descriptor pointers */
+	int 			rx_curr_desc_q, rx_used_desc_q;
+
+	/* Tx descriptor pointers */
+	int 			tx_curr_desc_q, tx_used_desc_q;
+
+	/* Rx descriptor area */
+	volatile titan_ge_rx_desc	*rx_desc_area;
+	unsigned int			rx_desc_area_size;
+	struct sk_buff*			rx_skb[TITAN_GE_RX_QUEUE];
+
+	/* Tx Descriptor area */
+	volatile titan_ge_tx_desc	*tx_desc_area;
+	unsigned int                    tx_desc_area_size;
+	struct sk_buff*                 tx_skb[TITAN_GE_TX_QUEUE];
+
+	/* Timeout task */
+	struct tq_struct		tx_timeout_task;
+
+	/* DMA structures and handles */
+	dma_addr_t			tx_dma;
+	dma_addr_t			rx_dma;
+	dma_addr_t			tx_dma_array[TITAN_GE_TX_QUEUE];
+
+	/* Device lock */
+	spinlock_t			lock;
+
+	unsigned int			tx_ring_skbs;
+	unsigned int			rx_ring_size;
+	unsigned int			tx_ring_size;
+	unsigned int			rx_ring_skbs;
+
+	struct net_device_stats		stats;
+
+	/* Tx and Rx coalescing */
+	unsigned long			rx_int_coal;
+	unsigned long			tx_int_coal;
+
+	/* Threshold for replenishing the Rx and Tx rings */
+	unsigned int			tx_threshold;
+	unsigned int			rx_threshold;
+
+	/* NAPI work limit */
+	unsigned int			rx_work_limit;
+} titan_ge_port_info;
+
+/* Titan specific constants */
+#define	TITAN_ETH_PORT_IRQ		4
+
+/* Max Rx buffer */
+#define	TITAN_GE_MAX_RX_BUFFER		65536
+
+/* Tx and Rx Error */
+#define	TITAN_GE_ERROR
+
+/* Rx Descriptor Command and Status */
+
+#define	TITAN_GE_RX_CRC_ERROR		TITAN_BIT27	/* crc error */
+#define	TITAN_GE_RX_OVERFLOW_ERROR	TITAN_BIT15	/* overflow */
+#define TITAN_GE_RX_BUFFER_OWNED	TITAN_BIT21	/* buffer ownership */
+#define	TITAN_GE_RX_STP			TITAN_BIT31	/* start of packet */
+#define	TITAN_GE_RX_BAM			TITAN_BIT30	/* broadcast address match */
+#define TITAN_GE_RX_PAM			TITAN_BIT28	/* physical address match */
+#define TITAN_GE_RX_LAFM		TITAN_BIT29	/* logical address filter match */
+#define TITAN_GE_RX_VLAN		TITAN_BIT26	/* virtual lans */
+#define TITAN_GE_RX_PERR		TITAN_BIT19	/* packet error */
+#define TITAN_GE_RX_TRUNC		TITAN_BIT20	/* packet size greater than 32 buffers */
+
+/* Tx Descriptor Command */
+#define	TITAN_GE_TX_BUFFER_OWNED	TITAN_BIT5	/* buffer ownership */	
+#define	TITAN_GE_TX_ENABLE_INTERRUPT	TITAN_BIT15	/* Interrupt Enable */
+
+/* Return Status */
+#define	TITAN_OK	0x1	/* Good Status */
+#define	TITAN_ERROR	0x2	/* Error Status */
+
+/* MIB specific register offset */
+#define TITAN_GE_MSTATX_STATS_BASE_LOW       0x0800  /* MSTATX COUNTL[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_MID       0x0804  /* MSTATX COUNTM[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_HI        0x0808  /* MSTATX COUNTH[7:0] */
+#define TITAN_GE_MSTATX_CONTROL              0x0828  /* MSTATX Control */
+#define TITAN_GE_MSTATX_VARIABLE_SELECT      0x082C  /* MSTATX Variable Select */
+
+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */
+#define TITAN_GE_MSTATX_RXFRAMESOK                   0x0040
+#define TITAN_GE_MSTATX_RXOCTETSOK                   0x0050
+#define TITAN_GE_MSTATX_RXFRAMES                     0x0060
+#define TITAN_GE_MSTATX_RXOCTETS                     0x0070
+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK            0x0080
+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK          0x0090
+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK          0x00A0
+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK             0x00B0
+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK    0x00C0
+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK         0x00D0
+#define TITAN_GE_MSTATX_RXFCSERROR                   0x00E0
+#define TITAN_GE_MSTATX_RXALIGNMENTERROR             0x00F0
+#define TITAN_GE_MSTATX_RXSYMBOLERROR                0x0100
+#define TITAN_GE_MSTATX_RXLAYER1ERROR                0x0110
+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR         0x0120
+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR            0x0130
+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR         0x0140
+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR           0x0150
+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR       0x0160
+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS             0x0170
+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS        0x0180
+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS       0x0190
+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS       0x01A0
+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS      0x01B0
+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS     0x01C0
+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE        0x01D0
+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED     0x01E0
+#define TITAN_GE_MSTATX_RXVARIABLE                   0x01F0
+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED       0x0200
+#define TITAN_GE_MSTATX_UNICASTFILTERED              0x0210
+#define TITAN_GE_MSTATX_MULTICASTFILTERED            0x0220
+#define TITAN_GE_MSTATX_BROADCASTFILTERED            0x0230
+#define TITAN_GE_MSTATX_HASHFILTERED                 0x0240
+#define TITAN_GE_MSTATX_TXFRAMESOK                   0x0250
+#define TITAN_GE_MSTATX_TXOCTETSOK                   0x0260
+#define TITAN_GE_MSTATX_TXOCTETS                     0x0270
+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK             0x0280
+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK    0x0290
+#define TITAN_GE_MSTATX_TXFCSERROR                   0x02A0
+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR           0x02B0
+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR            0x02C0
+#define TITAN_GE_MSTATX_TXSYSTEMERROR                0x02D0
+#define TITAN_GE_MSTATX_TXMACERROR                   0x02E0
+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR          0x02F0
+#define TITAN_GE_MSTATX_TXSQETESTERROR               0x0300
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK            0x0310
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK          0x0320
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK          0x0330
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED     0x0340
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED   0x0350
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED   0x0360
+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS             0x0370
+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS        0x0380
+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS       0x0390
+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS       0x03A0
+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS      0x03B0
+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS     0x03C0
+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE        0x03D0
+#define TITAN_GE_MSTATX_TXVARIABLE                   0x03E0
+#define TITAN_GE_MSTATX_RXSYSTEMERROR                0x03F0
+#define TITAN_GE_MSTATX_SINGLECOLLISION              0x0400
+#define TITAN_GE_MSTATX_MULTIPLECOLLISION            0x0410
+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS            0x0420
+#define TITAN_GE_MSTATX_LATECOLLISIONS               0x0430
+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS          0x0440
+
+/* Interrupt specific defines */
+#define TITAN_GE_DEVICE_ID         0x0000  /* Device ID */
+#define TITAN_GE_RESET             0x0004  /* Reset reg */
+#define TITAN_GE_TSB_CTRL_0        0x000C  /* TSB Control reg 0 */
+#define TITAN_GE_TSB_CTRL_1        0x0010  /* TSB Control reg 1 */
+#define TITAN_GE_INTR_GRP0_STATUS  0x0040  /* General Interrupt Group 0 Status */
+#define TITAN_GE_INTR_XDMA_CORE_A  0x0048  /* XDMA Channel Interrupt Status, Core A*/
+#define TITAN_GE_INTR_XDMA_CORE_B  0x004C  /* XDMA Channel Interrupt Status, Core B*/
+#define	TITAN_GE_INTR_XDMA_IE	   0x0058  /* XDMA Channel Interrupt Enable */
+#define TITAN_GE_SDQPF_ECC_INTR    0x480C  /* SDQPF ECC Interrupt Status */
+#define TITAN_GE_SDQPF_RXFIFO_CTL  0x4828  /* SDQPF RxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C  /* SDQPF RxFifo Interrupt Status */
+#define TITAN_GE_SDQPF_TXFIFO_CTL  0x4928  /* SDQPF TxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C  /* SDQPF TxFifo Interrupt Status */
+#define	TITAN_GE_SDQPF_RXFIFO_0	   0x4840  /* SDQPF RxFIFO Enable */
+#define	TITAN_GE_SDQPF_TXFIFO_0	   0x4940  /* SDQPF TxFIFO Enable */
+#define TITAN_GE_XDMA_CONFIG       0x5000  /* XDMA Global Configuration */
+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010  /* XDMA Interrupt Summary */
+#define TITAN_GE_XDMA_BUFADDRPRE   0x5018  /* XDMA Buffer Address Prefix */
+#define TITAN_GE_XDMA_DESCADDRPRE  0x501C  /* XDMA Descriptor Address Prefix */
+#define TITAN_GE_XDMA_PORTWEIGHT   0x502C  /* XDMA Port Weight Configuration */
+
+/* Rx MAC defines */
+#define TITAN_GE_RMAC_CONFIG_1               0x1200  /* RMAC Configuration 1 */
+#define TITAN_GE_RMAC_CONFIG_2               0x1204  /* RMAC Configuration 2 */
+#define TITAN_GE_RMAC_MAX_FRAME_LEN          0x1208  /* RMAC Max Frame Length */
+#define TITAN_GE_RMAC_STATION_HI             0x120C  /* Rx Station Address High */
+#define TITAN_GE_RMAC_STATION_MID            0x1210  /* Rx Station Address Middle */
+#define TITAN_GE_RMAC_STATION_LOW            0x1214  /* Rx Station Address Low */
+#define TITAN_GE_RMAC_LINK_CONFIG            0x1218  /* RMAC Link Configuration */
+
+/* Tx MAC defines */
+#define TITAN_GE_TMAC_CONFIG_1               0x1240  /* TMAC Configuration 1 */
+#define TITAN_GE_TMAC_CONFIG_2               0x1244  /* TMAC Configuration 2 */
+#define TITAN_GE_TMAC_IPG                    0x1248  /* TMAC Inter-Packet Gap */
+#define TITAN_GE_TMAC_STATION_HI             0x124C  /* Tx Station Address High */
+#define TITAN_GE_TMAC_STATION_MID            0x1250  /* Tx Station Address Middle */
+#define TITAN_GE_TMAC_STATION_LOW            0x1254  /* Tx Station Address Low */
+#define TITAN_GE_TMAC_MAX_FRAME_LEN          0x1258  /* TMAC Max Frame Length */
+#define TITAN_GE_TMAC_MIN_FRAME_LEN          0x125C  /* TMAC Min Frame Length */
+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME       0x1260  /* TMAC Pause Frame Time */
+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL   0x1264  /* TMAC Pause Frame Interval */
+
+/* GMII register */
+#define TITAN_GE_GMII_INTERRUPT_STATUS       0x1348  /* GMII Interrupt Status */
+#define TITAN_GE_GMII_CONFIG_GENERAL         0x134C  /* GMII Configuration General */
+#define TITAN_GE_GMII_CONFIG_MODE            0x1350  /* GMII Configuration Mode */
+
+/* Tx and Rx XDMA defines */
+#define	TITAN_GE_INT_COALESCING		     0x5030 /* Interrupt Coalescing */
+#define	TITAN_GE_CHANNEL0_CONFIG	     0x5040 /* Channel 0 XDMA config */
+#define	TITAN_GE_CHANNEL0_INTERRUPT	     0x504c /* Channel 0 Interrupt Status */
+#define	TITAN_GE_GDI_INTERRUPT_ENABLE        0x5050 /* IE for the GDI Errors */
+#define	TITAN_GE_CHANNEL0_PACKET	     0x5060 /* Channel 0 Packet count */
+#define	TITAN_GE_CHANNEL0_BYTE		     0x5064 /* Channel 0 Byte count */
+#define	TITAN_GE_CHANNEL0_TX_DESC	     0x5054 /* Channel 0 Tx first desc */
+#define	TITAN_GE_CHANNEL0_RX_DESC	     0x5058 /* Channel 0 Rx first desc */
+
+/* AFX (Address Filter Exact) register offsets for Slice 0 */
+#define TITAN_GE_AFX_EXACT_MATCH_LOW         0x1100  /* AFX Exact Match Address Low*/
+#define TITAN_GE_AFX_EXACT_MATCH_MID         0x1104  /* AFX Exact Match Address Mid*/
+#define TITAN_GE_AFX_EXACT_MATCH_HIGH        0x1108  /* AFX Exact Match Address Hi */
+#define TITAN_GE_AFX_EXACT_MATCH_VID         0x110C  /* AFX Exact Match VID */
+#define TITAN_GE_AFX_MULTICAST_HASH_LOW      0x1110  /* AFX Multicast HASH Low */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW   0x1114  /* AFX Multicast HASH MidLow */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI    0x1118  /* AFX Multicast HASH MidHi */
+#define TITAN_GE_AFX_MULTICAST_HASH_HI       0x111C  /* AFX Multicast HASH Hi */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0     0x1120  /* AFX Address Filter Ctrl 0 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1     0x1124  /* AFX Address Filter Ctrl 1 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2     0x1128  /* AFX Address Filter Ctrl 2 */
+
+/* Traffic Groomer block */
+#define        TITAN_GE_TRTG_CONFIG	     0x1000  /* TRTG Config */
+
+#endif 				/* _TITAN_GE_H_ */
+
diff -urN linux-2.4.29-pre3/drivers/net/titan_mdio.c linux-2.4.29-rc1/drivers/net/titan_mdio.c
--- linux-2.4.29-pre3/drivers/net/titan_mdio.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/titan_mdio.c	2005-01-12 10:54:50.309666350 -0800
@@ -0,0 +1,217 @@
+/*
+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
+ * on the Titan. No support for the TBI as yet. 
+ *
+ */
+
+#include	"titan_mdio.h"
+
+#define MDIO_DEBUG
+
+/*
+ * Local constants
+ */
+#define MAX_CLKA            1023
+#define MAX_PHY_DEV         31
+#define MAX_PHY_REG         31
+#define WRITEADDRS_OPCODE   0x0
+#define	READ_OPCODE	    0x2
+#define WRITE_OPCODE        0x1
+#define MAX_MDIO_POLL       100
+
+/* 
+ * Titan MDIO and SCMB registers
+ */
+#define TITAN_GE_SCMB_CONTROL                0x01c0  /* SCMB Control */
+#define TITAN_GE_SCMB_CLKA	             0x01c4  /* SCMB Clock A */
+#define TITAN_GE_MDIO_COMMAND                0x01d0  /* MDIO Command */
+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS    0x01d4  /* MDIO Device and Port addrs */
+#define TITAN_GE_MDIO_DATA                   0x01d8  /* MDIO Data */
+#define TITAN_GE_MDIO_INTERRUPTS             0x01dC  /* MDIO Interrupts */
+
+/*
+ * Function to poll the MDIO 
+ */
+static int titan_ge_mdio_poll()
+{
+	int	i, val;
+
+	for (i = 0; i < MAX_MDIO_POLL; i++) {
+		val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+
+		if (!(val & 0x8000))
+			return TITAN_GE_MDIO_GOOD;
+	}
+
+	return TITAN_GE_MDIO_ERROR;
+}
+
+
+/*
+ * Initialize and configure the MDIO 
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
+{
+	unsigned long	val;
+
+	/* Reset the SCMB and program into MDIO mode*/
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
+
+	/* CLK A */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
+	val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
+
+	/* Preamble Suppresion */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	/* MDIO mode */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Set the PHY address in indirect mode
+ */
+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
+{
+	volatile unsigned long	val;
+
+	/* Setup the PHY device */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	/* Write the new address */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Read the MDIO register. This is what the individual parametes mean:
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register offset
+ *
+ * See the spec for the Titan MAC. We operate in the Direct Mode. 
+ */
+
+#define MAX_RETRIES	2
+
+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
+{
+	volatile unsigned long	val;
+	int retries = 0;
+
+	/* Setup the PHY device */
+
+again:
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	val |= 0x4000;
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+	
+	udelay(30);
+
+	/* Issue the read command */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	udelay(30);
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+		return TITAN_GE_MDIO_ERROR;
+
+	*pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
+
+	udelay(30);
+
+	if (val & 0x2) {
+		if (retries == MAX_RETRIES)
+			return TITAN_GE_MDIO_ERROR;
+		else {
+			retries++;
+			goto again;
+		}
+	}
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Write to the MDIO register 
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register that needs to be written to
+ *
+ */
+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
+{
+	volatile unsigned long	val;
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+		return TITAN_GE_MDIO_ERROR;
+
+	/* Setup the PHY device */
+        val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+        val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+        val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+	val |= 0x4000;
+        TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+	udelay(30);
+
+	/* Setup the data to write */
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
+
+	udelay(30);
+
+	/* Issue the write command */
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+	val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
+	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+	udelay(30);
+
+	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) 
+                return TITAN_GE_MDIO_ERROR;
+
+	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);	
+	if (val & 0x2)
+		return TITAN_GE_MDIO_ERROR;
+
+	return TITAN_GE_MDIO_GOOD;
+}
+
diff -urN linux-2.4.29-pre3/drivers/net/titan_mdio.h linux-2.4.29-rc1/drivers/net/titan_mdio.h
--- linux-2.4.29-pre3/drivers/net/titan_mdio.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/titan_mdio.h	2005-01-12 10:54:50.310666393 -0800
@@ -0,0 +1,59 @@
+/*
+ * MDIO used to interact with the PHY when using GMII/MII
+ */
+#ifndef _TITAN_MDIO_H
+#define _TITAN_MDIO_H
+
+#include <linux/netdevice.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+#include "titan_ge.h"
+
+
+#define	TITAN_GE_MDIO_ERROR	(-9000)
+#define	TITAN_GE_MDIO_GOOD	0
+
+#define	TITAN_GE_MDIO_BASE		TITAN_GE_BASE
+
+#define	TITAN_GE_MDIO_READ(offset)	*(volatile u32 *)(TITAN_GE_MDIO_BASE + offset)
+
+#define	TITAN_GE_MDIO_WRITE(offset, data)	\
+					*(volatile u32 *)(TITAN_GE_MDIO_BASE + offset) = data
+
+
+/* GMII specific registers */
+#define	TITAN_GE_MARVEL_PHY_ID		0x00
+#define	TITAN_PHY_AUTONEG_ADV		0x04
+#define	TITAN_PHY_LP_ABILITY		0x05
+#define	TITAN_GE_MDIO_MII_CTRL		0x09
+#define	TITAN_GE_MDIO_MII_EXTENDED	0x0f
+#define	TITAN_GE_MDIO_PHY_CTRL		0x10
+#define	TITAN_GE_MDIO_PHY_STATUS	0x11
+#define	TITAN_GE_MDIO_PHY_IE		0x12
+#define	TITAN_GE_MDIO_PHY_IS		0x13
+#define	TITAN_GE_MDIO_PHY_LED		0x18
+#define	TITAN_GE_MDIO_PHY_LED_OVER	0x19
+#define	PHY_ANEG_TIME_WAIT		45	/* 45 seconds wait time */
+
+/*
+ * MDIO Config Structure 
+ */
+typedef struct 
+{
+	unsigned int		clka;
+	int			mdio_spre;
+	int			mdio_mode;
+} titan_ge_mdio_config;
+
+/*
+ * Function Prototypes 
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *);
+int titan_ge_mdio_inaddrs(int, int);
+int titan_ge_mdio_read(int, int, unsigned int *);
+int titan_ge_mdio_write(int, int, unsigned int);
+
+#endif /* _TITAN_MDIO_H */
+		
+
+
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_38xx.c linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_38xx.c
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_38xx.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_38xx.c	2005-01-12 10:54:50.320666823 -0800
@@ -44,7 +44,7 @@
  *  register located at offset %ISL38XX_INT_IDENT_REG.
  */
 void
-isl38xx_disable_interrupts(void *device)
+isl38xx_disable_interrupts(void __iomem *device)
 {
 	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);
@@ -52,7 +52,7 @@
 
 void
 isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
-			     int *powerstate, void *device_base)
+			     int *powerstate, void __iomem *device_base)
 {
 	/* device requests to go into sleep mode
 	 * check whether the transmit queues for data and management are empty */
@@ -88,7 +88,7 @@
 
 void
 isl38xx_handle_wakeup(isl38xx_control_block *control_block,
-		      int *powerstate, void *device_base)
+		      int *powerstate, void __iomem *device_base)
 {
 	/* device is in active state, update the powerstate flag */
 	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
@@ -110,7 +110,7 @@
 }
 
 void
-isl38xx_trigger_device(int asleep, void *device_base)
+isl38xx_trigger_device(int asleep, void __iomem *device_base)
 {
 	struct timeval current_time;
 	u32 reg, counter = 0;
@@ -190,7 +190,7 @@
 }
 
 void
-isl38xx_interface_reset(void *device_base, dma_addr_t host_address)
+isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
 {
 #if VERBOSE > SHOW_ERROR_MESSAGES
 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
@@ -214,7 +214,7 @@
 }
 
 void
-isl38xx_enable_common_interrupts(void *device_base) {
+isl38xx_enable_common_interrupts(void __iomem *device_base) {
 	u32 reg;
 	reg = ( ISL38XX_INT_IDENT_UPDATE | 
 			ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_38xx.h linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_38xx.h
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_38xx.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_38xx.h	2005-01-12 10:54:50.321666865 -0800
@@ -75,7 +75,7 @@
  *  from the %ISL38XX_PCI_POSTING_FLUSH offset.
  */
 static inline void
-isl38xx_w32_flush(void *base, u32 val, unsigned long offset)
+isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
 {
 	writel(val, base + offset);
 	(void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
@@ -161,13 +161,13 @@
 /* determine number of entries currently in queue */
 int isl38xx_in_queue(isl38xx_control_block *cb, int queue);
 
-void isl38xx_disable_interrupts(void *);
-void isl38xx_enable_common_interrupts(void *);
+void isl38xx_disable_interrupts(void __iomem *);
+void isl38xx_enable_common_interrupts(void __iomem *);
 
 void isl38xx_handle_sleep_request(isl38xx_control_block *, int *,
-				  void *);
-void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *);
-void isl38xx_trigger_device(int, void *);
-void isl38xx_interface_reset(void *, dma_addr_t);
+				  void __iomem *);
+void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *);
+void isl38xx_trigger_device(int, void __iomem *);
+void isl38xx_interface_reset(void __iomem *, dma_addr_t);
 
 #endif				/* _ISL_38XX_H */
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_ioctl.c linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_ioctl.c
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/isl_ioctl.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/isl_ioctl.c	2005-01-12 10:54:50.323666951 -0800
@@ -1524,31 +1524,35 @@
 		     const struct obj_mlme *mlme, int error)
 {
 	union iwreq_data wrqu;
+	char *memptr;
 
-	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
-	if (!wrqu.data.pointer)
+	memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!memptr)
 		return;
+	wrqu.data.pointer = memptr;
 	wrqu.data.length = 0;
-	format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
+	format_event(priv, memptr, str, mlme, &wrqu.data.length,
 		     error);
-	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
-	kfree(wrqu.data.pointer);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+	kfree(memptr);
 }
 
 static void
 send_simple_event(islpci_private *priv, const char *str)
 {
 	union iwreq_data wrqu;
+	char *memptr;
 	int n = strlen(str);
 
-	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
-	if (!wrqu.data.pointer)
+	memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!memptr)
 		return;
 	BUG_ON(n > IW_CUSTOM_MAX);
+	wrqu.data.pointer = memptr;
 	wrqu.data.length = n;
-	strcpy(wrqu.data.pointer, str);
-	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
-	kfree(wrqu.data.pointer);
+	strcpy(memptr, str);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+	kfree(memptr);
 }
 
 static void
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_dev.c linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_dev.c
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_dev.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_dev.c	2005-01-12 10:54:50.324666994 -0800
@@ -58,7 +58,7 @@
 isl_upload_firmware(islpci_private *priv)
 {
 	u32 reg, rc;
-	void *device_base = priv->device_base;
+	void __iomem *device_base = priv->device_base;
 
 	/* clear the RAMBoot and the Reset bit */
 	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
@@ -113,7 +113,7 @@
 			    (fw_len >
 			     ISL38XX_MEMORY_WINDOW_SIZE) ?
 			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
-			u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
+			u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
 
 			/* set the cards base address for writting the data */
 			isl38xx_w32_flush(device_base, reg,
@@ -187,7 +187,7 @@
 	u32 reg;
 	islpci_private *priv = config;
 	struct net_device *ndev = priv->ndev;
-	void *device = priv->device_base;
+	void __iomem *device = priv->device_base;
 	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;
 
 	/* lock the interrupt handler */
@@ -407,7 +407,7 @@
 static int
 prism54_bring_down(islpci_private *priv)
 {
-	void *device_base = priv->device_base;
+	void __iomem *device_base = priv->device_base;
 	u32 reg;
 	/* we are going to shutdown the device */
 	islpci_set_state(priv, PRV_STATE_PREBOOT);
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_dev.h linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_dev.h
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_dev.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_dev.h	2005-01-12 10:54:50.324666994 -0800
@@ -113,7 +113,7 @@
 	u32 pci_state[16];	/* used for suspend/resume */
 	char firmware[33];
 
-	void *device_base;	/* ioremapped device base address */
+	void __iomem *device_base;	/* ioremapped device base address */
 
 	/* consistent DMA region */
 	void *driver_mem_address;	/* base DMA address */
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_hotplug.c linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_hotplug.c
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/islpci_hotplug.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/islpci_hotplug.c	2005-01-12 10:54:50.325667037 -0800
@@ -292,6 +292,8 @@
 	islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
 	BUG_ON(!priv);
 
+	pci_enable_device(pdev);
+
 	printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
 
 	pci_restore_state(pdev, priv->pci_state);
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/prismcompat.h linux-2.4.29-rc1/drivers/net/wireless/prism54/prismcompat.h
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/prismcompat.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/prismcompat.h	2005-01-12 10:54:50.325667037 -0800
@@ -38,6 +38,10 @@
 #error Firmware Loading is not configured in the kernel !
 #endif
 
+#ifndef __iomem
+#define __iomem
+#endif
+
 #define prism54_synchronize_irq(irq) synchronize_irq(irq)
 
 #define PRISM_FW_PDEV		&priv->pdev->dev
diff -urN linux-2.4.29-pre3/drivers/net/wireless/prism54/prismcompat24.h linux-2.4.29-rc1/drivers/net/wireless/prism54/prismcompat24.h
--- linux-2.4.29-pre3/drivers/net/wireless/prism54/prismcompat24.h	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc1/drivers/net/wireless/prism54/prismcompat24.h	2005-01-12 10:54:50.326667080 -0800
@@ -51,6 +51,10 @@
 #define INIT_WORK		INIT_TQUEUE
 #define schedule_work		schedule_task
 
+#ifndef __iomem
+#define __iomem
+#endif
+
 #if !defined(HAVE_NETDEV_PRIV)
 #define netdev_priv(x)		(x)->priv
 #endif
diff -urN linux-2.4.29-pre3/drivers/scsi/ahci.c linux-2.4.29-rc1/drivers/scsi/ahci.c
--- linux-2.4.29-pre3/drivers/scsi/ahci.c	2005-01-12 10:54:47.014524747 -0800
+++ linux-2.4.29-rc1/drivers/scsi/ahci.c	2005-01-12 10:54:50.408670604 -0800
@@ -241,9 +241,13 @@
 
 static struct pci_device_id ahci_pci_tbl[] = {
 	{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },
+	  board_ahci }, /* ICH6 */
 	{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },
+	  board_ahci }, /* ICH6M */
+	{ PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7 */
+	{ PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7M */
 	{ }	/* terminate list */
 };
 
diff -urN linux-2.4.29-pre3/drivers/scsi/ata_piix.c linux-2.4.29-rc1/drivers/scsi/ata_piix.c
--- linux-2.4.29-pre3/drivers/scsi/ata_piix.c	2005-01-12 10:54:47.015524790 -0800
+++ linux-2.4.29-rc1/drivers/scsi/ata_piix.c	2005-01-12 10:54:50.409670647 -0800
@@ -60,6 +60,7 @@
 	piix4_pata		= 2,
 	ich6_sata		= 3,
 	ich6_sata_rm		= 4,
+	ich7_sata		= 5,
 };
 
 static int piix_init_one (struct pci_dev *pdev,
@@ -90,6 +91,8 @@
 	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
 	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
 	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
 
 	{ }	/* terminate list */
 };
@@ -237,6 +240,18 @@
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
 	},
+
+	/* ich7_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
 };
 
 static struct pci_bits piix_enable_bits[] = {
diff -urN linux-2.4.29-pre3/drivers/scsi/libata-core.c linux-2.4.29-rc1/drivers/scsi/libata-core.c
--- linux-2.4.29-pre3/drivers/scsi/libata-core.c	2005-01-12 10:54:47.023525134 -0800
+++ linux-2.4.29-rc1/drivers/scsi/libata-core.c	2005-01-12 10:54:50.417670991 -0800
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
@@ -1918,7 +1919,24 @@
 	if (idx)
 		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
+/**
+ *	ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ *	@qc: Metadata associated with taskfile to check
+ *
+ *	LOCKING:
+ *	RETURNS: 0 when ATAPI DMA can be used
+ *               nonzero otherwise
+ */
+int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	int rc = 0; /* Assume ATAPI DMA is OK by default */
+
+	if (ap->ops->check_atapi_dma)
+		rc = ap->ops->check_atapi_dma(qc);
 
+	return rc;
+}
 /**
  *	ata_qc_prep - Prepare taskfile for submission
  *	@qc: Metadata associated with taskfile to be prepared
@@ -2368,6 +2386,9 @@
 	unsigned long timeout = 0;
 
 	switch (ap->pio_task_state) {
+	case PIO_ST_IDLE:
+		return;
+
 	case PIO_ST:
 		ata_pio_block(ap);
 		break;
@@ -2384,7 +2405,7 @@
 	case PIO_ST_TMOUT:
 	case PIO_ST_ERR:
 		ata_pio_error(ap);
-		break;
+		return;
 	}
 
 	if (timeout) {
@@ -2392,11 +2413,7 @@
 		schedule_timeout(timeout);
 	}
 
-	if ((ap->pio_task_state != PIO_ST_IDLE) &&
-	    (ap->pio_task_state != PIO_ST_TMOUT) &&
-	    (ap->pio_task_state != PIO_ST_ERR)) {
-		schedule_task(&ap->pio_task);
-	}
+	schedule_task(&ap->pio_task);
 }
 
 static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
@@ -2405,7 +2422,6 @@
 	DECLARE_COMPLETION(wait);
 	struct ata_queued_cmd *qc;
 	unsigned long flags;
-	int using_pio = dev->flags & ATA_DFLAG_PIO;
 	int rc;
 
 	DPRINTK("ATAPI request sense\n");
@@ -2426,16 +2442,10 @@
 	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	qc->tf.command = ATA_CMD_PACKET;
 
-	if (using_pio) {
-		qc->tf.protocol = ATA_PROT_ATAPI;
-		qc->tf.lbam = (8 * 1024) & 0xff;
-		qc->tf.lbah = (8 * 1024) >> 8;
-
-		qc->nbytes = SCSI_SENSE_BUFFERSIZE;
-	} else {
-		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
-		qc->tf.feature |= ATAPI_PKT_DMA;
-	}
+	qc->tf.protocol = ATA_PROT_ATAPI;
+	qc->tf.lbam = (8 * 1024) & 0xff;
+	qc->tf.lbah = (8 * 1024) >> 8;
+	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
 
 	qc->waiting = &wait;
 	qc->complete_fn = ata_qc_complete_noop;
@@ -2707,7 +2717,7 @@
 			return 1;
 
 		/* fall through */
-	
+
 	default:
 		return 0;
 	}
diff -urN linux-2.4.29-pre3/drivers/scsi/libata-scsi.c linux-2.4.29-rc1/drivers/scsi/libata-scsi.c
--- linux-2.4.29-pre3/drivers/scsi/libata-scsi.c	2005-01-12 10:54:47.025525220 -0800
+++ linux-2.4.29-rc1/drivers/scsi/libata-scsi.c	2005-01-12 10:54:50.419671077 -0800
@@ -1256,6 +1256,11 @@
 	int using_pio = (dev->flags & ATA_DFLAG_PIO);
 	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
 
+	if (!using_pio)
+		/* Check whether ATAPI DMA is safe */
+		if (ata_check_atapi_dma(qc))
+			using_pio = 1;
+
 	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
 
 	qc->complete_fn = atapi_qc_complete;
diff -urN linux-2.4.29-pre3/drivers/scsi/libata.h linux-2.4.29-rc1/drivers/scsi/libata.h
--- linux-2.4.29-pre3/drivers/scsi/libata.h	2005-01-12 10:54:47.025525220 -0800
+++ linux-2.4.29-rc1/drivers/scsi/libata.h	2005-01-12 10:54:50.420671120 -0800
@@ -38,6 +38,7 @@
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
 				      struct ata_device *dev);
 extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
diff -urN linux-2.4.29-pre3/drivers/scsi/sata_nv.c linux-2.4.29-rc1/drivers/scsi/sata_nv.c
--- linux-2.4.29-pre3/drivers/scsi/sata_nv.c	2005-01-12 10:54:47.026525263 -0800
+++ linux-2.4.29-rc1/drivers/scsi/sata_nv.c	2005-01-12 10:54:50.421671163 -0800
@@ -219,10 +219,18 @@
 	.host_stop		= nv_host_stop,
 };
 
+/* FIXME: The hardware provides the necessary SATA PHY controls
+ * to support ATA_FLAG_SATA_RESET.  However, it is currently
+ * necessary to disable that flag, to solve misdetection problems.
+ * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info.
+ *
+ * This problem really needs to be investigated further.  But in the
+ * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
+ */
 static struct ata_port_info nv_port_info = {
 	.sht		= &nv_sht,
 	.host_flags	= ATA_FLAG_SATA |
-			  ATA_FLAG_SATA_RESET |
+			  /* ATA_FLAG_SATA_RESET | */
 			  ATA_FLAG_SRST |
 			  ATA_FLAG_NO_LEGACY,
 	.pio_mask	= NV_PIO_MASK,
diff -urN linux-2.4.29-pre3/drivers/scsi/sata_uli.c linux-2.4.29-rc1/drivers/scsi/sata_uli.c
--- linux-2.4.29-pre3/drivers/scsi/sata_uli.c	2005-01-12 10:54:47.031525477 -0800
+++ linux-2.4.29-rc1/drivers/scsi/sata_uli.c	2005-01-12 10:54:50.426671378 -0800
@@ -32,16 +32,18 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_uli"
-#define DRV_VERSION	"0.2"
+#define DRV_VERSION	"0.5"
 
 enum {
 	uli_5289		= 0,
 	uli_5287		= 1,
+	uli_5281		= 2,
 
 	/* PCI configuration registers */
-	ULI_SCR_BASE		= 0x90, /* sata0 phy SCR registers */
-	ULI_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
-
+	ULI5287_BASE		= 0x90, /* sata0 phy SCR registers */
+	ULI5287_OFFS		= 0x10, /* offset from sata0->sata1 phy regs */
+	ULI5281_BASE		= 0x60, /* sata0 phy SCR  registers */
+	ULI5281_OFFS		= 0x60, /* offset from sata0->sata1 phy regs */
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -51,6 +53,7 @@
 static struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
 	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
 	{ }	/* terminate list */
 };
 
@@ -126,33 +129,15 @@
 MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
 {
-	unsigned int addr = ULI_SCR_BASE + (4 * sc_reg);
-
-	switch (port_no) {
-	case 0:
-		break;
-	case 1:
-		addr += ULI_SATA1_OFS;
-		break;
-	case 2:
-		addr += ULI_SATA1_OFS*4;
-		break;
-	case 3:
-		addr += ULI_SATA1_OFS*5;
-		break;
-	default:
-		BUG();
-		break;
-	}
-	return addr;
+	return ap->ioaddr.scr_addr + (4 * sc_reg);
 }
 
 static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
 	u32 val;
 
 	pci_read_config_dword(pdev, cfg_addr, &val);
@@ -162,7 +147,7 @@
 static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
 
 	pci_write_config_dword(pdev, cfg_addr, val);
 }
@@ -220,9 +205,11 @@
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
-
+	
 	switch (board_idx) {
 	case uli_5287:
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
        		probe_ent->n_ports = 4;
 
        		probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
@@ -230,19 +217,27 @@
 		probe_ent->port[2].ctl_addr =
 			(pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
 		probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+		probe_ent->port[2].scr_addr = ULI5287_BASE + ULI5287_OFFS*4;
 
 		probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
 		probe_ent->port[3].altstatus_addr =
 		probe_ent->port[3].ctl_addr =
 			(pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
 		probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+		probe_ent->port[3].scr_addr = ULI5287_BASE + ULI5287_OFFS*5;
 
 		ata_std_ports(&probe_ent->port[2]);
 		ata_std_ports(&probe_ent->port[3]);
 		break;
 
 	case uli_5289:
-		/* do nothing; ata_pci_init_native_mode did it all */
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+		break;
+
+	case uli_5281:
+		probe_ent->port[0].scr_addr = ULI5281_BASE;
+		probe_ent->port[1].scr_addr = ULI5281_BASE + ULI5281_OFFS;
 		break;
 
 	default:
diff -urN linux-2.4.29-pre3/drivers/usb/serial/ftdi_sio.c linux-2.4.29-rc1/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.29-pre3/drivers/usb/serial/ftdi_sio.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.29-rc1/drivers/usb/serial/ftdi_sio.c	2005-01-12 10:54:50.495674343 -0800
@@ -449,6 +449,12 @@
 };
 
 
+static struct usb_device_id id_table_userdev [] = {
+	{ USB_DEVICE(-1, -1) },
+	{ }						/* Terminating entry */
+};
+
+
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
@@ -548,6 +554,10 @@
 #define BUFSZ 512
 #define PKTSZ 64
 
+static int vendor =-1, product = -1, baud_base = 48000000/2; 
+    /* User specified VID and Product ID and baud base.  */ 
+
+
 struct ftdi_private {
 	ftdi_chip_type_t chip_type;
 				/* type of the device, either SIO or FT8U232AM */
@@ -584,6 +594,7 @@
 static int  ftdi_FT232BM_startup	(struct usb_serial *serial);
 static int  ftdi_USB_UIRT_startup	(struct usb_serial *serial);
 static int  ftdi_HE_TIRA1_startup	(struct usb_serial *serial);
+static int  ftdi_userdev_startup	(struct usb_serial *serial);
 static void ftdi_shutdown		(struct usb_serial *serial);
 static int  ftdi_open			(struct usb_serial_port *port, struct file *filp);
 static void ftdi_close			(struct usb_serial_port *port, struct file *filp);
@@ -727,6 +738,28 @@
 
 
 
+
+static struct usb_serial_device_type ftdi_userdev_device = {
+	.owner =		THIS_MODULE,
+	.name =			"FTDI SIO compatible",
+	.id_table =		id_table_userdev,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_userdev_startup,
+	.shutdown =		ftdi_shutdown,
+};
+
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
 /* High and low are for DTR, RTS etc etc */
@@ -1216,6 +1249,30 @@
  */
 
 
+/* Startup for the 8U232AM chip */
+static int ftdi_userdev_startup (struct usb_serial *serial)
+{
+	struct ftdi_private *priv;
+
+	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+	if (!priv){
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
+		return -ENOMEM;
+	}
+
+	priv->chip_type = FT8U232AM; /* XXX: Hmm. Keep this.... -- REW */
+	priv->baud_base = baud_base; 
+	priv->custom_divisor = 0;
+	priv->write_offset = 0;
+        init_waitqueue_head(&priv->delta_msr_wait);
+	/* This will push the characters through immediately rather
+	   than queue a task to deliver them */
+	priv->flags = ASYNC_LOW_LATENCY;
+	
+	return (0);
+}
+
+
 static void ftdi_shutdown (struct usb_serial *serial)
 { /* ftdi_shutdown */
 	
@@ -2134,6 +2191,14 @@
 	usb_serial_register (&ftdi_USB_UIRT_device);
 	usb_serial_register (&ftdi_HE_TIRA1_device);
 
+	if (vendor != -1) {
+		/* User specified USB vendor and device id */
+		/* The macro initialized "matchvendor" as the matching flags */
+		id_table_userdev[0].idVendor = vendor; 
+		id_table_userdev[0].idProduct = product;
+		usb_serial_register (&ftdi_userdev_device);
+	}
+	
 
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
@@ -2164,3 +2229,8 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
diff -urN linux-2.4.29-pre3/fs/binfmt_aout.c linux-2.4.29-rc1/fs/binfmt_aout.c
--- linux-2.4.29-pre3/fs/binfmt_aout.c	2005-01-12 10:54:47.082527669 -0800
+++ linux-2.4.29-rc1/fs/binfmt_aout.c	2005-01-12 10:54:50.542676363 -0800
@@ -46,7 +46,7 @@
 	start = PAGE_ALIGN(start);
 	end = PAGE_ALIGN(end);
 	if (end > start) {
-		unsigned long addr = do_brk(start, end - start);
+		unsigned long addr = do_brk_locked(start, end - start);
 		if (BAD_ADDR(addr))
 			return addr;
 	}
@@ -317,10 +317,10 @@
 		loff_t pos = fd_offset;
 		/* Fuck me plenty... */
 		/* <AOL></AOL> */
-		error = do_brk(N_TXTADDR(ex), ex.a_text);
+		error = do_brk_locked(N_TXTADDR(ex), ex.a_text);
 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 			  ex.a_text, &pos);
-		error = do_brk(N_DATADDR(ex), ex.a_data);
+		error = do_brk_locked(N_DATADDR(ex), ex.a_data);
 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
 			  ex.a_data, &pos);
 		goto beyond_if;
@@ -341,7 +341,7 @@
 		map_size = ex.a_text+ex.a_data;
 #endif
 
-		error = do_brk(text_addr & PAGE_MASK, map_size);
+		error = do_brk_locked(text_addr & PAGE_MASK, map_size);
 		if (error != (text_addr & PAGE_MASK)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -375,7 +375,7 @@
 
 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
 			loff_t pos = fd_offset;
-			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
+			do_brk_locked(N_TXTADDR(ex), ex.a_text+ex.a_data);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 					ex.a_text+ex.a_data, &pos);
 			flush_icache_range((unsigned long) N_TXTADDR(ex),
@@ -476,7 +476,7 @@
 			error_time = jiffies;
 		}
 
-		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
+		do_brk_locked(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 		
 		file->f_op->read(file, (char *)start_addr,
 			ex.a_text + ex.a_data, &pos);
@@ -500,7 +500,7 @@
 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len) {
-		error = do_brk(start_addr + len, bss - len);
+		error = do_brk_locked(start_addr + len, bss - len);
 		retval = error;
 		if (error != start_addr + len)
 			goto out;
diff -urN linux-2.4.29-pre3/fs/binfmt_elf.c linux-2.4.29-rc1/fs/binfmt_elf.c
--- linux-2.4.29-pre3/fs/binfmt_elf.c	2005-01-12 10:54:47.084527755 -0800
+++ linux-2.4.29-rc1/fs/binfmt_elf.c	2005-01-12 10:54:50.544676449 -0800
@@ -84,7 +84,7 @@
 	start = ELF_PAGEALIGN(start);
 	end = ELF_PAGEALIGN(end);
 	if (end > start) {
-		unsigned long addr = do_brk(start, end - start);
+		unsigned long addr = do_brk_locked(start, end - start);
 		if (BAD_ADDR(addr))
 			return addr;
 	}
@@ -290,7 +290,9 @@
 	 */
 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
 		goto out;
-	if (interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
+
+	if (interp_elf_ex->e_phnum < 1 ||
+	    interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
 		goto out;
 
 	/* Now read in all of the header information */
@@ -377,7 +379,7 @@
 
 	/* Map the last of the bss segment */
 	if (last_bss > elf_bss) {
-		error = do_brk(elf_bss, last_bss - elf_bss);
+		error = do_brk_locked(elf_bss, last_bss - elf_bss);
 		if (BAD_ADDR(error))
 			goto out_close;
 	}
@@ -423,7 +425,7 @@
 		goto out;
 	}
 
-	do_brk(0, text_data);
+	do_brk_locked(0, text_data);
 	if (!interpreter->f_op || !interpreter->f_op->read)
 		goto out;
 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
@@ -431,7 +433,7 @@
 	flush_icache_range((unsigned long)addr,
 	                   (unsigned long)addr + text_data);
 
-	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
+	do_brk_locked(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
 		interp_ex->a_bss);
 	elf_entry = interp_ex->a_entry;
 
@@ -972,7 +974,7 @@
 	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
 	if (bss > len)
-		do_brk(len, bss - len);
+		do_brk_locked(len, bss - len);
 	error = 0;
 
 out_free_ph:
diff -urN linux-2.4.29-pre3/include/linux/auto_fs4.h linux-2.4.29-rc1/include/linux/auto_fs4.h
--- linux-2.4.29-pre3/include/linux/auto_fs4.h	2001-11-22 11:46:40.000000000 -0800
+++ linux-2.4.29-rc1/include/linux/auto_fs4.h	2005-01-12 10:54:50.657681305 -0800
@@ -41,7 +41,10 @@
 	struct autofs_packet_expire_multi expire_multi;
 };
 
-#define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int)
-
+#define AUTOFS_IOC_EXPIRE_MULTI		_IOW(0x93,0x66,int)
+#define AUTOFS_IOC_PROTOSUBVER		_IOR(0x93,0x67,int)
+#define AUTOFS_IOC_ASKREGHOST		_IOR(0x93,0x68,int)
+#define AUTOFS_IOC_TOGGLEREGHOST	_IOR(0x93,0x69,int)
+#define AUTOFS_IOC_ASKUMOUNT		_IOR(0x93,0x70,int)
 
 #endif /* _LINUX_AUTO_FS4_H */
diff -urN linux-2.4.29-pre3/include/linux/libata.h linux-2.4.29-rc1/include/linux/libata.h
--- linux-2.4.29-pre3/include/linux/libata.h	2005-01-12 10:54:47.214533342 -0800
+++ linux-2.4.29-rc1/include/linux/libata.h	2005-01-12 10:54:50.665681649 -0800
@@ -340,6 +340,8 @@
 	void (*phy_reset) (struct ata_port *ap);
 	void (*post_set_mode) (struct ata_port *ap);
 
+	int (*check_atapi_dma) (struct ata_queued_cmd *qc);
+
 	void (*bmdma_setup) (struct ata_queued_cmd *qc);
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
 
diff -urN linux-2.4.29-pre3/include/linux/mm.h linux-2.4.29-rc1/include/linux/mm.h
--- linux-2.4.29-pre3/include/linux/mm.h	2005-01-12 10:54:47.215533385 -0800
+++ linux-2.4.29-rc1/include/linux/mm.h	2005-01-12 10:54:50.666681692 -0800
@@ -575,6 +575,7 @@
 extern int do_munmap(struct mm_struct *, unsigned long, size_t);
 
 extern unsigned long do_brk(unsigned long, unsigned long);
+extern unsigned long do_brk_locked(unsigned long, unsigned long);
 
 static inline void __vma_unlink(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev)
 {
diff -urN linux-2.4.29-pre3/include/linux/pci_ids.h linux-2.4.29-rc1/include/linux/pci_ids.h
--- linux-2.4.29-pre3/include/linux/pci_ids.h	2005-01-12 10:54:47.217533471 -0800
+++ linux-2.4.29-rc1/include/linux/pci_ids.h	2005-01-12 10:54:50.669681821 -0800
@@ -2064,6 +2064,9 @@
 #define PCI_DEVICE_ID_TIGERJET_300	0x0001
 #define PCI_DEVICE_ID_TIGERJET_100	0x0002
 
+#define PCI_VENDOR_ID_TTTECH		0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322	0x000A
+
 #define PCI_VENDOR_ID_ARK		0xedd8
 #define PCI_DEVICE_ID_ARK_STING		0xa091
 #define PCI_DEVICE_ID_ARK_STINGARK	0xa099
diff -urN linux-2.4.29-pre3/kernel/ksyms.c linux-2.4.29-rc1/kernel/ksyms.c
--- linux-2.4.29-pre3/kernel/ksyms.c	2004-02-18 05:36:32.000000000 -0800
+++ linux-2.4.29-rc1/kernel/ksyms.c	2005-01-12 10:54:50.680682294 -0800
@@ -88,6 +88,7 @@
 EXPORT_SYMBOL(do_mmap_pgoff);
 EXPORT_SYMBOL(do_munmap);
 EXPORT_SYMBOL(do_brk);
+EXPORT_SYMBOL(do_brk_locked);
 EXPORT_SYMBOL(exit_mm);
 EXPORT_SYMBOL(exit_files);
 EXPORT_SYMBOL(exit_fs);
diff -urN linux-2.4.29-pre3/mm/mmap.c linux-2.4.29-rc1/mm/mmap.c
--- linux-2.4.29-pre3/mm/mmap.c	2005-01-12 10:54:47.232534115 -0800
+++ linux-2.4.29-rc1/mm/mmap.c	2005-01-12 10:54:50.684682465 -0800
@@ -1116,6 +1116,21 @@
 	return addr;
 }
 
+/* locking version of do_brk. */
+unsigned long do_brk_locked(unsigned long addr, unsigned long len)
+{
+	unsigned long ret;
+
+	down_write(&current->mm->mmap_sem);
+	ret = do_brk(addr, len);
+	up_write(&current->mm->mmap_sem);
+
+	return ret;
+}
+
+
+
+
 /* Build the RB tree corresponding to the VMA list. */
 void build_mmap_rb(struct mm_struct * mm)
 {
diff -urN linux-2.4.29-pre3/net/Config.in linux-2.4.29-rc1/net/Config.in
--- linux-2.4.29-pre3/net/Config.in	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc1/net/Config.in	2005-01-12 10:54:50.688682637 -0800
@@ -61,7 +61,9 @@
 fi
 
 tristate 'Appletalk protocol support' CONFIG_ATALK
-source drivers/net/appletalk/Config.in
+if [ "$CONFIG_ATALK" != "n" ]; then
+   source drivers/net/appletalk/Config.in
+fi
 
 tristate 'DECnet Support' CONFIG_DECNET
 if [ "$CONFIG_DECNET" != "n" ]; then
