## Automatically generated incremental diff
## From:   linux-2.2.17-pre7
## To:     linux-2.2.17-pre8
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.2.17-pre7/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.17-pre7/Documentation/Configure.help	Mon Dec  3 22:07:14 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:07:25 2001
@@ -11442,10 +11442,18 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-BMAC (G3 ethernet) support
+Use AAUI port instead of TP by default
+CONFIG_MACE_AAUI_PORT
+  Some Apple machines (notably the Apple Network Server) which use the
+  MACE ethernet chip have an Apple AUI port (small 15-pin connector),
+  instead of an 8-pin RJ45 connector for twisted-pair ethernet.  Say
+  Y here if you have such a machine.  If unsure, say N.
+
+BMAC (G3/G4 ethernet) support
 CONFIG_BMAC
-  Say Y for support of BMAC Ethernet interfaces. These are used on G3
-  computers. 
+  Say Y for support of BMAC and BMAC+ Ethernet interfaces. These
+  are used on G3 and G4 computers (Apple Power Macintoshes and
+  PowerBooks).
 
   This driver is also available as a module called bmac.o ( = code
   which can be inserted in and removed from the running kernel
diff -urN linux-2.2.17-pre7/Makefile linux/Makefile
--- linux-2.2.17-pre7/Makefile	Mon Dec  3 22:07:14 2001
+++ linux/Makefile	Mon Dec  3 22:07:25 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre7
+EXTRAVERSION = pre8
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.17-pre7/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c
--- linux-2.2.17-pre7/arch/ppc/chrpboot/main.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/chrpboot/main.c	Mon Dec  3 22:07:25 2001
@@ -41,6 +41,8 @@
     unsigned char *im;
     unsigned initrd_start, initrd_size;
 
+    printf("chrpboot starting: loaded at 0x%x\n\r", _start);
+
     if (initrd_len) {
 	initrd_size = initrd_len;
 	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
diff -urN linux-2.2.17-pre7/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- linux-2.2.17-pre7/arch/ppc/coffboot/Makefile	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/coffboot/Makefile	Mon Dec  3 22:07:25 2001
@@ -135,5 +135,6 @@
 clean:
 	rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz
 	rm -f mknote piggyback vmlinux.elf note
+	rm -f micoffboot miboot.image
 
 fastdep:
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/apus_setup.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/apus_setup.c	Mon Dec  3 22:07:25 2001
@@ -42,7 +42,7 @@
 #include <asm/machdep.h>
 #include <asm/ide.h>
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 
 unsigned long apus_get_rtc_time(void);
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 22:07:25 2001
@@ -48,7 +48,7 @@
 #include <asm/adb.h>
 #include <asm/hydra.h>
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 #include "i8259.h"
 #include "open_pic.h"
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c
--- linux-2.2.17-pre7/arch/ppc/kernel/chrp_time.c	Fri Mar 19 10:50:03 1999
+++ linux/arch/ppc/kernel/chrp_time.c	Mon Dec  3 22:07:25 2001
@@ -25,7 +25,7 @@
 #include <asm/processor.h>
 #include <asm/nvram.h>
 #include <asm/prom.h>
-#include "time.h"
+#include <asm/time.h>
 
 static int nvram_as1 = NVRAM_AS1;
 static int nvram_as0 = NVRAM_AS0;
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/gemini_setup.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/gemini_setup.c	Mon Dec  3 22:07:25 2001
@@ -30,7 +30,7 @@
 #include <asm/m48t35.h>
 #include <asm/gemini.h>
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 #include "open_pic.h"
 
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/mbx_setup.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/mbx_setup.c	Mon Dec  3 22:07:25 2001
@@ -41,7 +41,7 @@
 #include <asm/mbx.h>
 #include <asm/machdep.h>
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 
 static int mbx_set_rtc_time(unsigned long time);
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 22:07:25 2001
@@ -58,7 +58,7 @@
 #include <asm/ide.h>
 #include <asm/machdep.h>
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 #include "pmac_pic.h"
 
@@ -371,9 +371,15 @@
 __initfunc(static void init_uninorth(void))
 {
 	/* 
-	 * Turns on the gmac clock so that it responds to PCI cycles
-	 * later, the driver may want to turn it off again to save
-	 * power when interface is down
+	 * Turns OFF the gmac clock. The gmac driver will turn
+	 * it back ON when the interface is enabled. This save
+	 * power on portables.
+	 * 
+	 * Note: We could also try to turn OFF the PHY. Since this
+	 * has to be done by both the gmac driver and this code,
+	 * I'll probably end-up moving some of this out of the
+	 * modular gmac driver into a non-modular stub containing
+	 * some basic PHY management and power management stuffs
 	 */
 	struct device_node* uni_n = find_devices("uni-n");
 	struct device_node* gmac = find_devices("ethernet");
@@ -389,7 +395,7 @@
 		gmac = gmac->next;
 	}
 	if (gmac) {
-		*(addr + 8) |= 2;
+		*(addr + 8) &= ~0x00000002UL;
 		eieio();
 	}
 }
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- linux-2.2.17-pre7/arch/ppc/kernel/pmac_support.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/pmac_support.c	Mon Dec  3 22:07:25 2001
@@ -42,18 +42,18 @@
 
 /* CHRP NVRAM header */
 struct chrp_header {
-  u8		signature;
-  u8		cksum;
-  u16		len;
-  char          name[12];
-  u8		data[0];
+	u8	signature;
+	u8	cksum;
+	u16	len;
+	char    name[12];
+	u8	data[0];
 };
 
 struct core99_header {
-  struct chrp_header	hdr;
-  u32			adler;
-  u32			generation;
-  u32			reserved[2];
+	struct chrp_header hdr;
+	u32	adler;
+	u32	generation;
+	u32	reserved[2];
 };
 
 /*
@@ -78,7 +78,6 @@
 
 extern int pmac_newworld;
 
-
 static u8
 chrp_checksum(struct chrp_header* hdr)
 {
@@ -206,6 +205,7 @@
 		hdr = (struct chrp_header *)buffer;
 	
 		offset = 0;
+		buffer[16] = 0;
 		do {
 			for (i=0;i<16;i++)
 				buffer[i] = nvram_read_byte(offset+i);
@@ -281,7 +281,7 @@
 	} else if (nvram_naddrs == 2) {
 		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && adb_hardware == ADB_VIAPMU) {
+	} else if (nvram_naddrs == 0 && adb_controller->kind == ADB_VIAPMU) {
 		nvram_naddrs = -1;
 	} else {
 		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- linux-2.2.17-pre7/arch/ppc/kernel/pmac_time.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/pmac_time.c	Mon Dec  3 22:07:25 2001
@@ -24,7 +24,7 @@
 #include <asm/pgtable.h>
 #include <asm/nvram.h>
 
-#include "time.h"
+#include <asm/time.h>
 
 /* Apparently the RTC stores seconds since 1 Jan 1904 */
 #define RTC_OFFSET	2082844800
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.2.17-pre7/arch/ppc/kernel/ppc_ksyms.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Dec  3 22:07:25 2001
@@ -30,6 +30,7 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/nvram.h>
+#include <asm/time.h>
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- linux-2.2.17-pre7/arch/ppc/kernel/prep_setup.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Dec  3 22:07:25 2001
@@ -48,7 +48,7 @@
 #include <asm/raven.h>
 
 
-#include "time.h"
+#include <asm/time.h>
 #include "local_irq.h"
 #include "i8259.h"
 #include "open_pic.h"
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
--- linux-2.2.17-pre7/arch/ppc/kernel/prep_time.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/prep_time.c	Mon Dec  3 22:07:25 2001
@@ -26,7 +26,7 @@
 #include <asm/prep_nvram.h>
 #include <asm/mk48t59.h>
 
-#include "time.h"
+#include <asm/time.h>
 
 /*
  * The motorola uses the m48t18 rtc (includes DS1643) whose registers
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- linux-2.2.17-pre7/arch/ppc/kernel/prom.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/prom.c	Mon Dec  3 22:07:25 2001
@@ -2034,15 +2034,6 @@
 	}
 }
 
-void
-here(int n)
-{
-	chrp_indicator(n);
-	if (n == 1)
-		clearscreen();
-	showvalue("here ", n);
-}
-
 __pmac
 void
 drawstring(const char *c)
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- linux-2.2.17-pre7/arch/ppc/kernel/smp.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/smp.c	Mon Dec  3 22:07:25 2001
@@ -35,8 +35,8 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/gemini.h>
-
-#include "time.h"
+#include <asm/residual.h>
+#include <asm/time.h>
 #include "open_pic.h"
 
 int first_cpu_booted = 0;
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- linux-2.2.17-pre7/arch/ppc/kernel/time.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/kernel/time.c	Mon Dec  3 22:07:25 2001
@@ -46,7 +46,7 @@
 #endif
 #include <asm/machdep.h>
 
-#include "time.h"
+#include <asm/time.h>
 
 void smp_local_timer_interrupt(struct pt_regs *);
 
diff -urN linux-2.2.17-pre7/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h
--- linux-2.2.17-pre7/arch/ppc/kernel/time.h	Tue Oct 26 17:53:39 1999
+++ linux/arch/ppc/kernel/time.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- * $Id: time.h,v 1.11.2.1 1999/08/27 04:20:35 cort Exp $
- * Common time prototypes and such for all ppc machines.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu) to merge
- * Paul Mackerras' version and mine for PReP and Pmac.
- */
-
-#include <linux/mc146818rtc.h>
-
-/* time.c */
-extern unsigned decrementer_count;
-extern unsigned count_period_num;
-extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
-			    unsigned int, unsigned int, unsigned int);
-extern void to_tm(int tim, struct rtc_time * tm);
-extern time_t last_rtc_update;
-
-int via_calibrate_decr(void);
-
-/* Accessor functions for the decrementer register. */
-static __inline__ unsigned int get_dec(void)
-{
-	unsigned int ret;
-
-	asm volatile("mfspr %0,22" : "=r" (ret) :);
-	return ret;
-}
-
-static __inline__ void set_dec(unsigned int val)
-{
-	asm volatile("mtspr 22,%0" : : "r" (val));
-}
diff -urN linux-2.2.17-pre7/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.2.17-pre7/arch/ppc/mm/init.c	Mon Dec  3 22:07:14 2001
+++ linux/arch/ppc/mm/init.c	Mon Dec  3 22:07:25 2001
@@ -420,7 +420,7 @@
 	   is now necessary.  This has been well tested on a Motorola
 	   MPC750 (Mesquite) processor board.  Johnnie Peters
 	*/
-	if (addr > high_memory && addr < ioremap_bot)
+	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
 		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
 
@@ -1391,7 +1391,7 @@
 	if (boot_infos == 0) {
 		/* record which bits the prom is using */
 		get_mem_prop("available", &phys_avail);
-		remove_mem_piece(&phys_avail, __max_memory, ~0U, 0);
+		remove_mem_piece(&phys_avail, __max_memory, ~__max_memory, 0);
 		prom_mem = phys_mem;
 		for (i = 0; i < phys_avail.n_regions; ++i)
 			remove_mem_piece(&prom_mem,
diff -urN linux-2.2.17-pre7/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.2.17-pre7/arch/sparc64/defconfig	Wed Jun  7 14:26:42 2000
+++ linux/arch/sparc64/defconfig	Mon Dec  3 22:07:25 2001
@@ -30,8 +30,9 @@
 CONFIG_FB_PM2=y
 # CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 CONFIG_FB_PM2_PCI=y
-# CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY128 is not set
 CONFIG_FB_SBUS=y
 CONFIG_FB_CREATOR=y
 CONFIG_FB_CGSIX=y
diff -urN linux-2.2.17-pre7/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- linux-2.2.17-pre7/drivers/char/adbmouse.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/char/adbmouse.c	Mon Dec  3 22:07:25 2001
@@ -35,6 +35,7 @@
 
 #include <asm/adb_mouse.h>
 #include <asm/uaccess.h>
+#include <asm/hardirq.h>
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
@@ -56,7 +57,7 @@
  *	XXX: need to figure out what ADB mouse packets mean ... 
  *	This is the stuff stolen from the Atari driver ...
  */
-static void adb_mouse_interrupt(unsigned char *buf, int nb)
+void adb_mouse_interrupt(unsigned char *buf, int nb)
 {
     int buttons, id;
 
@@ -154,6 +155,7 @@
       return 0;
 
     adb_mouse_interrupt_hook = NULL;
+    synchronize_irq();
     MOD_DEC_USE_COUNT;
     return 0;
 }
diff -urN linux-2.2.17-pre7/drivers/macintosh/rtc.c linux/drivers/macintosh/rtc.c
--- linux-2.2.17-pre7/drivers/macintosh/rtc.c	Mon Dec  3 22:07:14 2001
+++ linux/drivers/macintosh/rtc.c	Mon Dec  3 22:07:25 2001
@@ -26,10 +26,7 @@
 #include <asm/uaccess.h>
 #include <asm/machdep.h>
 
-/* in kernel/time.c, these prototypes shouldn't be here */
-extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
-                            unsigned int, unsigned int, unsigned int);
-extern void to_tm(int tim, struct rtc_time * tm);
+#include <asm/time.h>
 
 static int rtc_busy = 0;
 
diff -urN linux-2.2.17-pre7/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- linux-2.2.17-pre7/drivers/macintosh/via-pmu.c	Mon Dec  3 22:07:14 2001
+++ linux/drivers/macintosh/via-pmu.c	Mon Dec  3 22:07:25 2001
@@ -106,7 +106,7 @@
 static int pmu_fully_inited = 0;
 static int pmu_has_adb, pmu_has_backlight;
 static unsigned char *gpio_reg = NULL;
-static int gpio_irq;
+static int gpio_irq = -1;
 
 int asleep;
 
@@ -238,9 +238,19 @@
 	else if (device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
 	else if (device_is_compatible(vias->parent, "Keylargo")) {
+		struct device_node *gpio, *gpiop;
+
 		pmu_kind = PMU_KEYLARGO_BASED;
 		pmu_has_adb = (find_type_devices("adb") != NULL);
 		pmu_has_backlight = (find_type_devices("backlight") != NULL);
+
+		gpiop = find_devices("gpio");
+		if (gpiop && gpiop->n_addrs) {
+			gpio_reg = ioremap(gpiop->addrs->address, 0x10);
+			gpio = find_devices("extint-gpio1");
+			if (gpio && gpio->parent == gpiop && gpio->n_intrs)
+				gpio_irq = gpio->intrs[0].line;
+		}
 	} else
 		pmu_kind = PMU_UNKNOWN;
 
@@ -281,21 +291,9 @@
 		return;
 	}
 
-	if (pmu_kind == PMU_KEYLARGO_BASED) {
-		struct device_node *gpio, *gpiop;
-
-		gpiop = find_devices("gpio");
-		if (gpiop && gpiop->n_addrs) {
-			gpio_reg = ioremap(gpiop->addrs->address, 0x10);
-			gpio = find_devices("extint-gpio1");
-			if (gpio && gpio->parent == gpiop && gpio->n_intrs) {
-				gpio_irq = gpio->intrs[0].line;
-				if (request_irq(gpio_irq, gpio1_interrupt, 0,
-						"GPIO1/ADB", (void *)0))
-					printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n",
-					       gpio->intrs[0].line);
-			}
-		}
+	if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
+		if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0))
+			printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
 	}
 
 	/* Enable interrupts */
diff -urN linux-2.2.17-pre7/drivers/net/bmac.c linux/drivers/net/bmac.c
--- linux-2.2.17-pre7/drivers/net/bmac.c	Wed Aug 25 17:29:48 1999
+++ linux/drivers/net/bmac.c	Mon Dec  3 22:07:25 2001
@@ -1628,9 +1628,9 @@
     bp = (struct bmac_data *) bmac_devs->priv;
     unregister_netdev(bmac_devs);
 
-    free_irq(bmac_devs->irq, bmac_misc_intr);
-    free_irq(bp->tx_dma_intr, bmac_txdma_intr);
-    free_irq(bp->rx_dma_intr, bmac_rxdma_intr);
+    free_irq(bmac_devs->irq, dev);
+    free_irq(bp->tx_dma_intr, dev);
+    free_irq(bp->rx_dma_intr, dev);
 
 #ifdef CONFIG_PMAC_PBOOK
     pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
diff -urN linux-2.2.17-pre7/drivers/net/gmac.c linux/drivers/net/gmac.c
--- linux-2.2.17-pre7/drivers/net/gmac.c	Mon Dec  3 22:07:14 2001
+++ linux/drivers/net/gmac.c	Mon Dec  3 22:07:25 2001
@@ -2,95 +2,88 @@
  * Network device driver for the GMAC ethernet controller on
  * Apple G4 Powermacs.
  *
- * Copyright (C) 2000 Paul Mackerras.
+ * Copyright (C) 2000 Paul Mackerras & Ben. Herrenschmidt
+ * 
+ * portions based on sunhme.c by David S. Miller
+ *
  */
 
 #include <linux/module.h>
+
+#include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/pci.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/bitops.h>
+
 #include "gmac.h"
 
 #define DEBUG_PHY
 
-#define NTX		32		/* must be power of 2 */
-#define NRX		32		/* must be power of 2 */
-#define RX_BUFLEN	(ETH_FRAME_LEN + 8)
-
-struct gmac_dma_desc {
-	unsigned int	cmd;
-	unsigned int	status;
-	unsigned int	address;	/* phys addr, low 32 bits */
-	unsigned int	hi_addr;
-};
-
-/* Bits in cmd */
-#define RX_OWN	0x80000000		/* 1 = owned by chip */
-#define TX_SOP	0x80000000
-#define TX_EOP	0x40000000
-
-struct gmac {
-	volatile unsigned int *regs;	/* hardware registers, virtual addr */
-	volatile unsigned int *sysregs;
-	unsigned long	desc_page;	/* page for DMA descriptors */
-	volatile struct gmac_dma_desc *rxring;
-	struct sk_buff	*rx_buff[NRX];
-	int		next_rx;
-	volatile struct gmac_dma_desc *txring;
-	struct sk_buff	*tx_buff[NTX];
-	int		next_tx;
-	int		tx_gone;
-	unsigned char	tx_full;
-	int		phy_addr;
-	int		full_duplex;
-	struct net_device_stats stats;
-};
-
-#define GM_OUT(r, v)	out_le32(gm->regs + (r)/4, (v))
-#define GM_IN(r)	in_le32(gm->regs + (r)/4)
-#define GM_BIS(r, v)	GM_OUT((r), GM_IN(r) | (v))
-#define GM_BIC(r, v)	GM_OUT((r), GM_IN(r) & ~(v))
+/* Driver version 1.1, kernel 2.2.x */
+#define GMAC_VERSION	"v1.1k2"
 
-#define PHY_B5400	0x6040
-#define PHY_B5201	0x6212
-
-static unsigned char dummy_buf[RX_BUFLEN+2];
+static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN];
 static struct device *gmacs = NULL;
 
 /* Prototypes */
 static int mii_read(struct gmac *gm, int phy, int r);
 static int mii_write(struct gmac *gm, int phy, int r, int v);
-static void powerup_transceiver(struct gmac *gm);
-static int gmac_reset(struct device *dev);
+static void mii_poll_start(struct gmac *gm);
+static void mii_poll_stop(struct gmac *gm);
+static void mii_interrupt(struct gmac *gm);
+static int mii_lookup_and_reset(struct gmac *gm);
+static void mii_setup_phy(struct gmac *gm);
+
+static void gmac_set_power(struct gmac *gm, int power_up);
+static int gmac_powerup_and_reset(struct device *dev);
+static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex);
 static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
-static void gmac_init_rings(struct gmac *gm);
+static void gmac_init_rings(struct gmac *gm, int from_irq);
 static void gmac_start_dma(struct gmac *gm);
+static void gmac_stop_dma(struct gmac *gm);
+static void gmac_set_multicast(struct device *dev);
 static int gmac_open(struct device *dev);
 static int gmac_close(struct device *dev);
+static void gmac_tx_timeout(struct device *dev);
 static int gmac_xmit_start(struct sk_buff *skb, struct device *dev);
-static int gmac_tx_cleanup(struct gmac *gm);
+static void gmac_tx_cleanup(struct device *dev, int force_cleanup);
 static void gmac_receive(struct device *dev);
 static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats *gmac_stats(struct device *dev);
 int gmac_probe(struct device *dev);
 
+extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+		   unsigned char *devfn_ptr);
+
 /* Stuff for talking to the physical-layer chip */
 static int
 mii_read(struct gmac *gm, int phy, int r)
 {
 	int timeout;
 
-	GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18));
+	GM_OUT(GM_MIF_FRAME_CTL_DATA,
+		(0x01 << GM_MIF_FRAME_START_SHIFT) |
+		(0x02 << GM_MIF_FRAME_OPCODE_SHIFT) |
+		GM_MIF_FRAME_TURNAROUND_HI |
+		(phy << GM_MIF_FRAME_PHY_ADDR_SHIFT) |
+		(r << GM_MIF_FRAME_REG_ADDR_SHIFT));
+		
 	for (timeout = 1000; timeout > 0; --timeout) {
 		udelay(20);
-		if (GM_IN(MIFFRAME) & 0x10000)
-			return GM_IN(MIFFRAME) & 0xffff;
+		if (GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_TURNAROUND_LO)
+			return GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_DATA_MASK;
 	}
 	return -1;
 }
@@ -100,10 +93,17 @@
 {
 	int timeout;
 
-	GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff));
+	GM_OUT(GM_MIF_FRAME_CTL_DATA,
+		(0x01 << GM_MIF_FRAME_START_SHIFT) |
+		(0x01 << GM_MIF_FRAME_OPCODE_SHIFT) |
+		GM_MIF_FRAME_TURNAROUND_HI |
+		(phy << GM_MIF_FRAME_PHY_ADDR_SHIFT) |
+		(r << GM_MIF_FRAME_REG_ADDR_SHIFT) |
+		(v & GM_MIF_FRAME_DATA_MASK));
+
 	for (timeout = 1000; timeout > 0; --timeout) {
 		udelay(20);
-		if (GM_IN(MIFFRAME) & 0x10000)
+		if (GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_TURNAROUND_LO)
 			return 0;
 	}
 	return -1;
@@ -115,245 +115,573 @@
 	unsigned int tmp;
 	
 	/* Start the MIF polling on the external transceiver. */
-	tmp = GM_IN(MIFCONFIG);
-	tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK);
-	tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT);
-	tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT);
-	tmp |= GMAC_MIF_CFGPE;
-	GM_OUT(MIFCONFIG, tmp);
+	tmp = GM_IN(GM_MIF_CFG);
+	tmp &= ~(GM_MIF_CFGPR_MASK | GM_MIF_CFGPD_MASK);
+	tmp |= ((gm->phy_addr & 0x1f) << GM_MIF_CFGPD_SHIFT);
+	tmp |= (MII_SR << GM_MIF_CFGPR_SHIFT);
+	tmp |= GM_MIF_CFGPE;
+	GM_OUT(GM_MIF_CFG, tmp);
 
 	/* Let the bits set. */
-	udelay(GMAC_MIF_POLL_DELAY);
+	udelay(GM_MIF_POLL_DELAY);
 
-	GM_OUT(MIFINTMASK, 0xffc0);
+	GM_OUT(GM_MIF_IRQ_MASK, 0xffc0);
 }
 
 static void 
 mii_poll_stop(struct gmac *gm)
 {
-	GM_OUT(MIFINTMASK, 0xffff);
-	GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE);
-	udelay(GMAC_MIF_POLL_DELAY);
+	GM_OUT(GM_MIF_IRQ_MASK, 0xffff);
+	GM_BIC(GM_MIF_CFG, GM_MIF_CFGPE);
+	udelay(GM_MIF_POLL_DELAY);
 }
 
 static void
 mii_interrupt(struct gmac *gm)
 {
-	unsigned long	flags;
 	int		phy_status;
+	int		lpar_ability;
 	
-	save_flags(flags);
-	cli();
-
 	mii_poll_stop(gm);
 
 	/* May the status change before polling is re-enabled ? */
 	mii_poll_start(gm);
 	
 	/* We read the Auxilliary Status Summary register */
-	phy_status = mii_read(gm, gm->phy_addr, 0x19);
+	phy_status = mii_read(gm, gm->phy_addr, MII_SR);
+	if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) {
+		int		full_duplex;
+		int		link_100;
 #ifdef DEBUG_PHY
-	printk("mii_interrupt, phy_status: %x\n", phy_status);
+		printk("Link state change, phy_status: 0x%04x\n", phy_status);
 #endif
-	/* Auto-neg. complete ? */
-	if (phy_status & 0x8000) {
-		int full_duplex = 0;
-		switch((phy_status >> 8) & 0x7) {
-			case 2:
-			case 5:
-				full_duplex = 1;
-				break;
-		}
-		if (full_duplex != gm->full_duplex) {
-			GM_BIC(TXMAC_CONFIG, 1);
-			udelay(200);
-			if (full_duplex) {
-				printk("full duplex active\n");
-				GM_OUT(TXMAC_CONFIG, 6);
-				GM_OUT(XIF_CONFIG, 1);
-			} else {
-				printk("half duplex active\n");
-				GM_OUT(TXMAC_CONFIG, 0);
-				GM_OUT(XIF_CONFIG, 5);
-			}
-			GM_BIS(TXMAC_CONFIG, 1);
+		gm->phy_status = phy_status;
+
+		lpar_ability = mii_read(gm, gm->phy_addr, MII_ANLPA);
+		if (lpar_ability & MII_ANLPA_PAUS)
+			GM_BIS(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
+		else
+			GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
+
+		/* Link ? For now we handle only the 5201 PHY */
+		if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
+		    if (gm->phy_type == PHY_B5201) {
+		    	int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
+#ifdef DEBUG_PHY
+			printk("    Link up ! BCM5201 aux_stat: 0x%04x\n", aux_stat);
+#endif
+		    	full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
+		    	link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
+		    } else {
+		    	full_duplex = 1;
+		    	link_100 = 1;
+		    }
+#ifdef DEBUG_PHY
+		    printk("    full_duplex: %d, speed: %s\n", full_duplex,
+		    	link_100 ? "100" : "10");
+#endif
+		    if (full_duplex != gm->full_duplex) {
 			gm->full_duplex = full_duplex;
+			gmac_set_duplex_mode(gm, gm->full_duplex);
+			gmac_start_dma(gm);
+		    }
+		} else if (!(phy_status & MII_SR_LKS)) {
+#ifdef DEBUG_PHY
+		    printk("    Link down !\n");
+#endif
 		}
 	}
-
-	restore_flags(flags);
 }
 
-static void
-powerup_transceiver(struct gmac *gm)
+static int
+mii_lookup_and_reset(struct gmac *gm)
 {
-	int phytype = mii_read(gm, 0, 3);
+	int	i, timeout;
+	int	mii_status, mii_control;
+
+	/* Find the PHY */
+	gm->phy_addr = -1;
+	gm->phy_type = PHY_UNKNOWN;
+	
+	for(i=31; i>0; --i) {
+		mii_control = mii_read(gm, i, MII_CR);
+		mii_status = mii_read(gm, i, MII_SR);
+		if (mii_control != -1  && mii_status != -1 &&
+			(mii_control != 0xffff || mii_status != 0xffff))
+			break;
+	}
+	gm->phy_addr = i;
+	if (gm->phy_addr < 0)
+		return 0;
+
+	/* Reset it */
+	mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST);
+	mdelay(10);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mii_read(gm, gm->phy_addr, MII_CR);
+		if (mii_control == -1) {
+			printk(KERN_ERR "%s PHY died after reset !\n",
+				gm->dev->name);
+			goto fail;
+		}
+		if ((mii_control & MII_CR_RST) == 0)
+			break;
+		mdelay(10);
+	}
+	if (mii_control & MII_CR_RST) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+		goto fail;
+	}
+	mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
+
+	/* Read the PHY ID */
+	gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
+		mii_read(gm, gm->phy_addr, MII_ID1);
 #ifdef DEBUG_PHY
-	int i;
-#endif	
-	switch (phytype) {
-	case PHY_B5400:
-		mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800);
-		mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8);
-		break;
-	case PHY_B5201:
-		mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8);
-		break;
-	default:
-		printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype);
+	printk("%s PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
+#endif
+	if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
+		gm->phy_type = PHY_B5400;
+		printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n",
+			gm->dev->name);
+	} else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
+		gm->phy_type = PHY_B5201;
+	} else {
+		printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n",
+			gm->dev->name, gm->phy_id);
 	}
-	/* Check this */
-	gm->phy_addr = 0;
-	gm->full_duplex = 0;
 
-#ifdef DEBUG_PHY
-	printk("PHY regs:\n");
-	for (i=0; i<0x20; i++) {
-		printk("%04x ", mii_read(gm, 0, i)); 
-		if ((i % 4) == 3)
-			printk("\n");
+	return 1;
+	
+fail:
+	gm->phy_addr = -1;
+	return 0;
+}
+
+/* Code to setup the PHY duplex mode and speed should be
+ * added here
+ */
+static void
+mii_setup_phy(struct gmac *gm)
+{
+	int data;
+	
+	/* Stop auto-negociation */
+	data = mii_read(gm, gm->phy_addr, MII_CR);
+	mii_write(gm, gm->phy_addr, MII_CR, data & ~MII_CR_ASSE);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mii_read(gm, gm->phy_addr, MII_ANA);
+	data |= MII_ANA_TXAM | MII_ANA_FDAM | MII_ANA_10M;
+	mii_write(gm, gm->phy_addr, MII_ANA, data);
+	
+	/* Restart auto-negociation */
+	data = mii_read(gm, gm->phy_addr, MII_CR);
+	data |= MII_CR_ASSE;
+	mii_write(gm, gm->phy_addr, MII_CR, data);
+	data |= MII_CR_RAN;
+	mii_write(gm, gm->phy_addr, MII_CR, data);
+}
+
+static void
+gmac_set_power(struct gmac *gm, int power_up)
+{
+	if (power_up) {
+		out_le32(gm->sysregs + 0x20/4,
+			in_le32(gm->sysregs + 0x20/4) | 0x02000000);
+		udelay(10);
+		if (gm->pci_devfn != 0xff) {
+			u16 cmd;
+			
+			/* Make sure PCI is correctly configured */
+			pcibios_read_config_word(gm->pci_bus, gm->pci_devfn,
+				PCI_COMMAND, &cmd);
+			cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+	    		pcibios_write_config_word(gm->pci_bus, gm->pci_devfn,
+	    			PCI_COMMAND, cmd);
+	    		pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,
+	    			PCI_LATENCY_TIMER, 16);
+	    		pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,
+	    			PCI_CACHE_LINE_SIZE, 8);
+		}
+	} else {
+		/* FIXME: Add PHY power down */
+		gm->phy_type = 0;
+		out_le32(gm->sysregs + 0x20/4,
+			in_le32(gm->sysregs + 0x20/4) & ~0x02000000);
 	}
-#endif
 }
 
 static int
-gmac_reset(struct device *dev)
+gmac_powerup_and_reset(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 	int timeout;
-
+	
 	/* turn on GB clock */
-	out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2);
-	udelay(10);
-	GM_OUT(SW_RESET, 3);
+	gmac_set_power(gm, 1);
+	/* Perform a software reset */
+	GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);
 	for (timeout = 100; timeout > 0; --timeout) {
 		mdelay(10);
-		if ((GM_IN(SW_RESET) & 3) == 0)
+		if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) {
+			/* Mask out all chips interrupts */
+			GM_OUT(GM_IRQ_MASK, 0xffffffff);
 			return 0;
+		}
 	}
-	printk(KERN_ERR "GMAC: reset failed!\n");
+	printk(KERN_ERR "%s reset failed!\n", dev->name);
+	gmac_set_power(gm, 0);
 	return -1;
 }
 
+/* Set the MAC duplex mode. Side effect: stops Tx MAC */
+static void
+gmac_set_duplex_mode(struct gmac *gm, int full_duplex)
+{
+	/* Stop Tx MAC */
+	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+	while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)
+		;
+	
+	if (full_duplex) {
+		GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER
+			| GM_MAC_TX_CONF_IGNORE_COLL);
+		GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);
+	} else {
+		GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER
+			| GM_MAC_TX_CONF_IGNORE_COLL);
+		GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);
+	}
+}
+
 static void
 gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
 {
-	int i;
+	int i, fifo_size;
 
-	GM_OUT(RANSEED, 937);
-	GM_OUT(DATAPATHMODE, 4);
-	mii_write(gm, 0, 0, 0x1000);
-	GM_OUT(TXDMA_CONFIG, 0xffc00);
-	GM_OUT(RXDMA_CONFIG, 0);
-	GM_OUT(MACPAUSE, 0x1bf0);
-	GM_OUT(IPG0, 0);
-	GM_OUT(IPG1, 8);
-	GM_OUT(IPG2, 4);
-	GM_OUT(MINFRAMESIZE, 64);
-	GM_OUT(MAXFRAMESIZE, 2000);
-	GM_OUT(PASIZE, 7);
-	GM_OUT(JAMSIZE, 4);
-	GM_OUT(ATTEMPT_LIMIT, 16);
-	GM_OUT(SLOTTIME, 64);
-	GM_OUT(MACCNTL_TYPE, 0x8808);
-	GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]);
-	GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]);
-	GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]);
-	GM_OUT(MAC_ADDR_3, 0);
-	GM_OUT(MAC_ADDR_4, 0);
-	GM_OUT(MAC_ADDR_5, 0);
-	GM_OUT(MAC_ADDR_6, 0x0180);
-	GM_OUT(MAC_ADDR_7, 0xc200);
-	GM_OUT(MAC_ADDR_8, 0x0001);
-	GM_OUT(MAC_ADDR_FILTER_0, 0);
-	GM_OUT(MAC_ADDR_FILTER_1, 0);
-	GM_OUT(MAC_ADDR_FILTER_2, 0);
-	GM_OUT(MAC_ADDR_FILTER_MASK21, 0);
-	GM_OUT(MAC_ADDR_FILTER_MASK0, 0);
+	/* Set random seed to low bits of MAC address */
+	GM_OUT(GM_MAC_RANDOM_SEED, mac_addr[5] | (mac_addr[4] << 8));
+	
+	/* Configure the data path mode to MII/GII */
+	GM_OUT(GM_PCS_DATAPATH_MODE, GM_PCS_DATAPATH_MII);
+	
+	/* Configure XIF to MII mode. Full duplex led is set
+	 * by Apple, so...
+	 */
+	GM_OUT(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_TX_MII_OUT_EN
+		| GM_MAC_XIF_CONF_FULL_DPLX_LED);
+
+	/* Mask out all MAC interrupts */
+	GM_OUT(GM_MAC_TX_MASK, 0xffff);
+	GM_OUT(GM_MAC_RX_MASK, 0xffff);
+	GM_OUT(GM_MAC_CTRLSTAT_MASK, 0xff);
+	
+	/* Setup bits of MAC */
+	GM_OUT(GM_MAC_SND_PAUSE, GM_MAC_SND_PAUSE_DEFAULT);
+	GM_OUT(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_RCV_PAUSE_EN);
+	
+	/* Configure GEM DMA */
+	GM_OUT(GM_GCONF, GM_GCONF_BURST_SZ |
+		(31 << GM_GCONF_TXDMA_LIMIT_SHIFT) |
+		(31 << GM_GCONF_RXDMA_LIMIT_SHIFT));
+	GM_OUT(GM_TX_CONF,
+		GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT |
+		NTX_CONF);
+/* 34 byte offset for checksum computation.  This works because ip_input() will clear out
+ * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
+ * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
+ */
+	GM_OUT(GM_RX_CONF,
+		(RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) |
+		(0x22 << GM_RX_CONF_CHK_START_SHIFT) |
+		NRX_CONF);
+
+	/* Configure other bits of MAC */
+	GM_OUT(GM_MAC_INTR_PKT_GAP0, GM_MAC_INTR_PKT_GAP0_DEFAULT);
+	GM_OUT(GM_MAC_INTR_PKT_GAP1, GM_MAC_INTR_PKT_GAP1_DEFAULT);
+	GM_OUT(GM_MAC_INTR_PKT_GAP2, GM_MAC_INTR_PKT_GAP2_DEFAULT);
+	GM_OUT(GM_MAC_MIN_FRAME_SIZE, GM_MAC_MIN_FRAME_SIZE_DEFAULT);
+	GM_OUT(GM_MAC_MAX_FRAME_SIZE, GM_MAC_MAX_FRAME_SIZE_DEFAULT);
+	GM_OUT(GM_MAC_PREAMBLE_LEN, GM_MAC_PREAMBLE_LEN_DEFAULT);
+	GM_OUT(GM_MAC_JAM_SIZE, GM_MAC_JAM_SIZE_DEFAULT);
+	GM_OUT(GM_MAC_ATTEMPT_LIMIT, GM_MAC_ATTEMPT_LIMIT_DEFAULT);
+	GM_OUT(GM_MAC_SLOT_TIME, GM_MAC_SLOT_TIME_DEFAULT);
+	GM_OUT(GM_MAC_CONTROL_TYPE, GM_MAC_CONTROL_TYPE_DEFAULT);
+	
+	/* Setup MAC addresses, clear filters, clear hash table */
+	GM_OUT(GM_MAC_ADDR_NORMAL0, (mac_addr[4] << 8) + mac_addr[5]);
+	GM_OUT(GM_MAC_ADDR_NORMAL1, (mac_addr[2] << 8) + mac_addr[3]);
+	GM_OUT(GM_MAC_ADDR_NORMAL2, (mac_addr[0] << 8) + mac_addr[1]);
+	GM_OUT(GM_MAC_ADDR_ALT0, 0);
+	GM_OUT(GM_MAC_ADDR_ALT1, 0);
+	GM_OUT(GM_MAC_ADDR_ALT2, 0);
+	GM_OUT(GM_MAC_ADDR_CTRL0, 0x0001);
+	GM_OUT(GM_MAC_ADDR_CTRL1, 0xc200);
+	GM_OUT(GM_MAC_ADDR_CTRL2, 0x0180);
+	GM_OUT(GM_MAC_ADDR_FILTER0, 0);
+	GM_OUT(GM_MAC_ADDR_FILTER1, 0);
+	GM_OUT(GM_MAC_ADDR_FILTER2, 0);
+	GM_OUT(GM_MAC_ADDR_FILTER_MASK1_2, 0);
+	GM_OUT(GM_MAC_ADDR_FILTER_MASK0, 0);
 	for (i = 0; i < 27; ++i)
-		GM_OUT(MAC_HASHTABLE + i, 0);
-	GM_OUT(MACCNTL_CONFIG, 0);
+		GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + i, 0);
+	
+	/* Clear stat counters */
+	GM_OUT(GM_MAC_COLLISION_CTR, 0);
+	GM_OUT(GM_MAC_FIRST_COLLISION_CTR, 0);
+	GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);
+	GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);
+	GM_OUT(GM_MAC_DEFER_TIMER_COUNTER, 0);
+	GM_OUT(GM_MAC_PEAK_ATTEMPTS, 0);
+	GM_OUT(GM_MAC_RX_FRAME_CTR, 0);
+	GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);
+	GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);
+	GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);
+	GM_OUT(GM_MAC_RX_CODE_VIOLATION_CTR, 0);
+	
 	/* default to half duplex */
-	GM_OUT(TXMAC_CONFIG, 0);
-	GM_OUT(XIF_CONFIG, 5);
+	GM_OUT(GM_MAC_TX_CONFIG, 0);
+	GM_OUT(GM_MAC_RX_CONFIG, 0);
+	gmac_set_duplex_mode(gm, gm->full_duplex);
+	
+	/* Setup pause thresholds */
+	fifo_size = GM_IN(GM_RX_FIFO_SIZE);
+	GM_OUT(GM_RX_PTH,
+		((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 2 / GM_RX_PTH_UNITS))
+			<< GM_RX_PTH_OFF_SHIFT) |
+		((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 3 / GM_RX_PTH_UNITS))
+			<< GM_RX_PTH_ON_SHIFT));
+		
+	/* Setup interrupt blanking */
+	if (GM_IN(GM_BIF_CFG) & GM_BIF_CFG_M66EN)
+		GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)
+			| (8 << GM_RX_BLANK_INTR_TIME_SHIFT));
+	else
+		GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)
+			| (4 << GM_RX_BLANK_INTR_TIME_SHIFT));	
 }
 
 static void
-gmac_init_rings(struct gmac *gm)
+gmac_init_rings(struct gmac *gm, int from_irq)
 {
 	int i;
 	struct sk_buff *skb;
 	unsigned char *data;
 	struct gmac_dma_desc *ring;
+	int gfp_flags = GFP_KERNEL;
+
+	if (from_irq || in_interrupt())
+		gfp_flags = GFP_ATOMIC;
 
 	/* init rx ring */
 	ring = (struct gmac_dma_desc *) gm->rxring;
 	memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
 	for (i = 0; i < NRX; ++i, ++ring) {
 		data = dummy_buf;
-		gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+		gm->rx_buff[i] = skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
 		if (skb != 0) {
-			/*skb_reserve(skb, 2);*/
-			data = skb->data;
+			skb->dev = gm->dev;
+			skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);
+			skb_reserve(skb, RX_OFFSET);
+			data = skb->data - RX_OFFSET;
 		}
-		st_le32(&ring->address, virt_to_bus(data));
-		st_le32(&ring->cmd, RX_OWN);
+		st_le32(&ring->lo_addr, virt_to_bus(data));
+		st_le32(&ring->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));
 	}
 
 	/* init tx ring */
 	ring = (struct gmac_dma_desc *) gm->txring;
-	memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+	memset(ring, 0, NTX * sizeof(struct gmac_dma_desc));
 
 	/* set pointers in chip */
 	mb();
-	GM_OUT(RXDMA_BASE_HIGH, 0);
-	GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring));
-	GM_OUT(TXDMA_BASE_HIGH, 0);
-	GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring));
+	GM_OUT(GM_RX_DESC_HI, 0);
+	GM_OUT(GM_RX_DESC_LO, virt_to_bus(gm->rxring));
+	GM_OUT(GM_TX_DESC_HI, 0);
+	GM_OUT(GM_TX_DESC_LO, virt_to_bus(gm->txring));
 }
 
 static void
 gmac_start_dma(struct gmac *gm)
 {
-	GM_BIS(RXDMA_CONFIG, 1);
-	GM_BIS(RXMAC_CONFIG, 1);
-	GM_OUT(RXDMA_KICK, NRX);
-	GM_BIS(TXDMA_CONFIG, 1);
-	GM_BIS(TXMAC_CONFIG, 1);
+	/* Enable Tx and Rx */
+	GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN);
+	mdelay(20);
+	GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN);
+	mdelay(20);
+	GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
+	mdelay(20);
+	GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+	mdelay(20);
+	/* Kick the receiver and enable interrupts */
+	GM_OUT(GM_RX_KICK, NRX);
+	GM_BIC(GM_IRQ_MASK, 	GM_IRQ_TX_INT_ME |
+				GM_IRQ_TX_ALL |
+				GM_IRQ_RX_DONE |
+				GM_IRQ_RX_TAG_ERR |
+				GM_IRQ_MAC_RX |
+				GM_IRQ_MIF |
+				GM_IRQ_BUS_ERROR);
+}
+
+static void
+gmac_stop_dma(struct gmac *gm)
+{
+	/* disable interrupts */
+	GM_OUT(GM_IRQ_MASK, 0xffffffff);
+	/* Enable Tx and Rx */
+	GM_BIC(GM_TX_CONF, GM_TX_CONF_DMA_EN);
+	mdelay(20);
+	GM_BIC(GM_RX_CONF, GM_RX_CONF_DMA_EN);
+	mdelay(20);
+	GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
+	mdelay(20);
+	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+	mdelay(20);
+}
+
+#define CRC_POLY	0xedb88320
+static void
+gmac_set_multicast(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	struct dev_mc_list *dmi = dev->mc_list;
+	int i,j,k,b;
+	unsigned long crc;
+	int multicast_hash = 0;
+	int multicast_all = 0;
+
+	/* Lock out others. */
+	set_bit(0, (void *) &dev->tbusy);
+
+	gm->promisc = 0;
+
+	if (dev->flags & IFF_PROMISC)
+		gm->promisc = 1;
+	else if ((dev->flags & IFF_ALLMULTI) /* || (dev->mc_count > XXX) */) {
+		multicast_all = 1;
+	} else {
+		u16 hash_table[16];
+
+		for(i = 0; i < 16; i++)
+			hash_table[i] = 0;
+
+	    	for (i = 0; i < dev->mc_count; i++) {
+			crc = ~0;
+			for (j = 0; j < 6; ++j) {
+			    b = dmi->dmi_addr[j];
+			    for (k = 0; k < 8; ++k) {
+				if ((crc ^ b) & 1)
+				    crc = (crc >> 1) ^ CRC_POLY;
+				else
+				    crc >>= 1;
+				b >>= 1;
+			    }
+			}
+			j = crc >> 24;	/* bit number in multicast_filter */
+			hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
+			dmi = dmi->next;
+	    	}
+
+	    	for (i = 0; i < 16; i++)
+	    		GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + (i*4), hash_table[i]);
+		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+	    	multicast_hash = 1;
+	}
+
+	if (gm->promisc)
+		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);
+	else
+		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);
+
+	if (multicast_hash)
+		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+	else
+		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+
+	if (multicast_all)
+		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);
+	else
+		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);
+	
+	/* Let us get going again. */
+	dev->tbusy = 0;
 }
 
-static int gmac_open(struct device *dev)
+static int
+gmac_open(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 
-	if (gmac_reset(dev))
+	MOD_INC_USE_COUNT;
+
+	/* Power up and reset chip */
+	if (gmac_powerup_and_reset(dev)) {
+		MOD_DEC_USE_COUNT;
 		return -EIO;
+	}
 
-	MOD_INC_USE_COUNT;
+	/* Get our interrupt */
+	if (request_irq(dev->irq, gmac_interrupt, 0, dev->name, dev)) {
+		printk(KERN_ERR "%s can't get irq %d\n", dev->name, dev->irq);
+		MOD_DEC_USE_COUNT;
+		return -EAGAIN;
+	}
+
+	gm->full_duplex = 0;
+	gm->phy_status = 0;
+	gm->promisc = 0;
+	
+	/* Find a PHY */
+	if (!mii_lookup_and_reset(gm))
+		printk(KERN_WARNING "%s WARNING ! Can't find PHY\n", dev->name);
 
-	powerup_transceiver(gm);
+	/* Configure the PHY */
+	mii_setup_phy(gm);
+	
+	/* Initialize the MAC */
 	gmac_mac_init(gm, dev->dev_addr);
-	gmac_init_rings(gm);
-	gmac_start_dma(gm);
+	
+	/* Initialize the descriptor rings */
+	gmac_init_rings(gm, 0);
+
+	/* Initialize the multicast tables & promisc mode if any */
+	gmac_set_multicast(dev);
+	
+	/*
+	 * Check out PHY status and start auto-poll
+	 * 
+	 * Note: do this before enabling interrutps
+	 */
 	mii_interrupt(gm);
 
-	GM_OUT(INTR_DISABLE, 0xfffdffe8);
+	/* Start the chip */
+	gmac_start_dma(gm);
+
+	gm->opened = 1;
 
 	return 0;
 }
 
-static int gmac_close(struct device *dev)
+static int
+gmac_close(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 	int i;
 
+	gm->opened = 0;
+	
+	gmac_stop_dma(gm);
+	
 	mii_poll_stop(gm);
 	
-	GM_BIC(RXDMA_CONFIG, 1);
-	GM_BIC(RXMAC_CONFIG, 1);
-	GM_BIC(TXDMA_CONFIG, 1);
-	GM_BIC(TXMAC_CONFIG, 1);
-	GM_OUT(INTR_DISABLE, ~0U);
+	free_irq(dev->irq, dev);
+
+	/* Shut down chip */
+	gmac_set_power(gm, 0);
+
 	for (i = 0; i < NRX; ++i) {
 		if (gm->rx_buff[i] != 0) {
 			dev_kfree_skb(gm->rx_buff[i]);
@@ -371,144 +699,315 @@
 	return 0;
 }
 
-static int gmac_xmit_start(struct sk_buff *skb, struct device *dev)
+/*
+ * Handle a transmit timeout
+ */
+static void
+gmac_tx_timeout(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
-	volatile struct gmac_dma_desc *dp;
+	int i;
 	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	
+	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+
+	/*
+	 * Do something useful here
+	 * 
+	 * FIXME: check if a complete re-init of the chip isn't necessary
+	 */
+
+	/* Stop chip */
+	gmac_stop_dma(gm);
+	/* Empty Tx ring of any remaining gremlins */
+	gmac_tx_cleanup(dev, 1);
+	/* Empty Rx ring of any remaining gremlins */
+	for (i = 0; i < NRX; ++i) {
+		if (gm->rx_buff[i] != 0) {
+			dev_kfree_skb(gm->rx_buff[i]);
+			gm->rx_buff[i] = 0;
+		}
+	}
+	/* Create fresh rings */
+	gmac_init_rings(gm, 1);
+	/* Restart PHY auto-poll */
+	mii_interrupt(gm);
+	/* Restart chip */
+	gmac_start_dma(gm);
+
+	restore_flags(flags);
+	
+	dev->tbusy = 0;
+}
+
+
+static int
+gmac_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	volatile struct gmac_dma_desc *dp;
 	int i;
 
-	save_flags(flags); cli();
+	/* Check tbusy bit and handle eventual transmitter timeout */
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+		int tickssofar = jiffies - dev->trans_start;
+	    
+		if (tickssofar >= 40)
+			gmac_tx_timeout(dev);
+		return 1;
+	}
+
 	i = gm->next_tx;
 	if (gm->tx_buff[i] != 0) {
 		/* buffer is full, can't send this packet at the moment */
-		dev->tbusy = 1;
-		gm->tx_full = 1;
-		restore_flags(flags);
 		return 1;
 	}
 	gm->next_tx = (i + 1) & (NTX - 1);
 	gm->tx_buff[i] = skb;
-	restore_flags(flags);
 
 	dp = &gm->txring[i];
-	dp->status = 0;
+	/* FIXME: Interrupt on all packet for now, change this to every N packet,
+	 * with N to be adjusted
+	 */
+	dp->flags = TX_FL_INTERRUPT;
 	dp->hi_addr = 0;
-	st_le32(&dp->address, virt_to_bus(skb->data));
+	st_le32(&dp->lo_addr, virt_to_bus(skb->data));
 	mb();
-	st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len);
+	st_le32(&dp->size, TX_SZ_SOP | TX_SZ_EOP | skb->len);
 	mb();
 
-	GM_OUT(TXDMA_KICK, gm->next_tx);
+	dev->trans_start = jiffies;
+	GM_OUT(GM_TX_KICK, gm->next_tx);
+
+	dev->tbusy = (gm->tx_buff[gm->next_tx] != 0);
 
 	return 0;
 }
 
-static int gmac_tx_cleanup(struct gmac *gm)
+/*
+ * Handle servicing of the transmit ring by deallocating used
+ * Tx packets and restoring flow control when necessary
+ */
+static void
+gmac_tx_cleanup(struct device *dev, int force_cleanup)
 {
-	int i = gm->tx_gone;
+	struct gmac *gm = (struct gmac *) dev->priv;
 	volatile struct gmac_dma_desc *dp;
 	struct sk_buff *skb;
-	int ret = 0;
-	int gone = GM_IN(TXDMA_COMPLETE);
+	int gone, i;
 
-	while (i != gone) {
+	i = gm->tx_gone;
+	gone = GM_IN(GM_TX_COMP);
+	
+	while (force_cleanup || i != gone) {
 		skb = gm->tx_buff[i];
 		if (skb == NULL)
 			break;
 		dp = &gm->txring[i];
-		gm->stats.tx_bytes += skb->len;
-		++gm->stats.tx_packets;
+		if (force_cleanup)
+			++gm->stats.tx_errors;
+		else {
+			++gm->stats.tx_packets;
+			gm->stats.tx_bytes += skb->len;
+		}
 		gm->tx_buff[i] = NULL;
 		dev_kfree_skb(skb);
 		if (++i >= NTX)
 			i = 0;
 	}
-	if (i != gm->tx_gone) {
-		ret = gm->tx_full;
-		gm->tx_gone = i;
-		gm->tx_full = 0;
-	}
-	return ret;
+	gm->tx_gone = i;
+
+	if (!force_cleanup && dev->tbusy &&
+	    (gm->tx_buff[gm->next_tx] == 0))
+		dev->tbusy = 0;
 }
 
-static void gmac_receive(struct device *dev)
+static void
+gmac_receive(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 	int i = gm->next_rx;
 	volatile struct gmac_dma_desc *dp;
-	struct sk_buff *skb;
-	int len;
+	struct sk_buff *skb, *new_skb;
+	int len, flags, drop;
 	unsigned char *data;
-
+	u16 csum;
+	
 	for (;;) {
 		dp = &gm->rxring[i];
-		if (ld_le32(&dp->cmd) & RX_OWN)
+		if (ld_le32(&dp->size) & RX_SZ_OWN)
 			break;
-		len = (ld_le32(&dp->cmd) >> 16) & 0x7fff;
+		len = (ld_le32(&dp->size) >> 16) & 0x7fff;
+		flags = ld_le32(&dp->flags);
 		skb = gm->rx_buff[i];
-		if (skb == 0) {
-			++gm->stats.rx_dropped;
-		} else if (ld_le32(&dp->status) & 0x40000000) {
+		drop = 0;
+		new_skb = NULL;
+		csum = ld_le32(&dp->size) & RX_SZ_CKSUM_MASK;
+		
+		/* Handle errors */
+		if ((len < ETH_ZLEN)||(flags & RX_FL_CRC_ERROR)||(!skb)) {
 			++gm->stats.rx_errors;
-			dev_kfree_skb(skb);
+			if (len < ETH_ZLEN)
+				++gm->stats.rx_length_errors;
+			if (flags & RX_FL_CRC_ERROR)
+				++gm->stats.rx_crc_errors;
+			if (!skb) {
+				++gm->stats.rx_dropped;
+				skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+				if (skb) {
+					gm->rx_buff[i] = skb;
+			    		skb->dev = dev;
+			    		skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);
+			    		skb_reserve(skb, RX_OFFSET);
+				}
+			}
+			drop = 1;
 		} else {
-			skb_put(skb, len);
-			skb->dev = dev;
+			/* Large packet, alloc a new skb for the ring */
+			if (len > RX_COPY_THRESHOLD) {
+			    new_skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+			    if(!new_skb) {
+			    	printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",
+			    		dev->name);
+			    	drop = 1;
+			    	++gm->stats.rx_dropped;
+			    	goto finish;
+			    }
+
+			    gm->rx_buff[i] = new_skb;
+			    new_skb->dev = dev;
+			    skb_put(new_skb, ETH_FRAME_LEN + RX_OFFSET);
+			    skb_reserve(new_skb, RX_OFFSET);
+			    skb_trim(skb, len);
+			} else {
+			    /* Small packet, copy it to a new small skb */
+			    struct sk_buff *copy_skb = dev_alloc_skb(len + RX_OFFSET);
+
+			    if(!copy_skb) {
+				printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",
+					dev->name);
+				drop = 1;
+				++gm->stats.rx_dropped;
+			    	goto finish;
+			    }
+
+			    copy_skb->dev = dev;
+			    skb_reserve(copy_skb, RX_OFFSET);
+			    skb_put(copy_skb, len);
+			    memcpy(copy_skb->data, skb->data, len);
+
+			    new_skb = skb;
+			    skb = copy_skb;
+			}
+		}
+	finish:
+		/* Need to drop packet ? */
+		if (drop) {
+			new_skb = skb;
+			skb = NULL;
+		}
+		
+		/* Put back ring entry */
+		data = new_skb ? (new_skb->data - RX_OFFSET) : dummy_buf;
+		dp->hi_addr = 0;
+		st_le32(&dp->lo_addr, virt_to_bus(data));
+		mb();
+		st_le32(&dp->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));
+		
+		/* Got Rx packet ? */
+		if (skb) {
+			/* Yes, baby, keep that hot ;) */
+			if(!(csum ^ 0xffff))
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			else
+				skb->ip_summed = CHECKSUM_NONE;
+			skb->ip_summed = CHECKSUM_NONE;
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			gm->stats.rx_bytes += skb->len;
 			++gm->stats.rx_packets;
 		}
-		data = dummy_buf;
-		gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
-		if (skb != 0) {
-			/*skb_reserve(skb, 2);*/
-			data = skb->data;
-		}
-		st_le32(&dp->address, virt_to_bus(data));
-		dp->hi_addr = 0;
-		mb();
-		st_le32(&dp->cmd, RX_OWN);
+		
 		if (++i >= NRX)
 			i = 0;
 	}
 	gm->next_rx = i;
 }
 
-static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void
+gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev = (struct device *) dev_id;
 	struct gmac *gm = (struct gmac *) dev->priv;
 	unsigned int status;
 
-	status = GM_IN(INTR_STATUS);
-	GM_OUT(INTR_ACK, status);
+	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+		printk(KERN_ERR "%s: Duplicate entry of the interrupt handler !\n",
+			   dev->name);
+		dev->interrupt = 0;
+		return;
+	}
+
+	status = GM_IN(GM_IRQ_STATUS);
+	GM_OUT(GM_IRQ_ACK, status);
 	
-	if (status & GMAC_IRQ_MIF) {
-		mii_interrupt(gm);
+	if (status & (GM_IRQ_RX_TAG_ERR | GM_IRQ_BUS_ERROR)) {
+		printk(KERN_ERR "%s: IRQ Error status: 0x%08x\n",
+			dev->name, status);
 	}
-	gmac_receive(dev);
-	if (gmac_tx_cleanup(gm)){
-		dev->tbusy = 0;
-		mark_bh(NET_BH);
+	
+	if (status & GM_IRQ_MIF) {
+		mii_interrupt(gm);
 	}
+
+	if (status & GM_IRQ_RX_DONE)
+		gmac_receive(dev);
+
+	if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL))
+		gmac_tx_cleanup(dev, 0);
+
+	dev->interrupt = 0;
 }
 
-static struct net_device_stats *gmac_stats(struct device *dev)
+static struct net_device_stats *
+gmac_stats(struct device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
+	struct net_device_stats *stats = &gm->stats;
+
+	if (gm && gm->opened) {
+		stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR);
+		GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);
+
+		stats->rx_frame_errors += GM_IN(GM_MAC_RX_ALIGN_ERR_CTR);
+		GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);
 
-	return &gm->stats;
+		stats->rx_length_errors += GM_IN(GM_MAC_RX_LEN_ERR_CTR);
+		GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);
+
+		stats->tx_aborted_errors += GM_IN(GM_MAC_EXCS_COLLISION_CTR);
+
+		stats->collisions +=
+			(GM_IN(GM_MAC_EXCS_COLLISION_CTR) +
+			 GM_IN(GM_MAC_LATE_COLLISION_CTR));
+		GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);
+		GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);
+	}
+	
+	return stats;
 }
 
-int gmac_probe(struct device *dev)
+int
+gmac_probe(struct device *dev)
 {
 	static int gmacs_found;
 	static struct device_node *next_gmac;
 	struct device_node *gmac;
 	struct gmac *gm;
-	unsigned long descpage;
+	unsigned long rx_descpage, tx_descpage;
 	unsigned char *addr;
 	int i;
 
@@ -530,6 +1029,19 @@
 		return -ENODEV;
 	}
 
+	rx_descpage = get_free_page(GFP_KERNEL);
+	if (rx_descpage == 0) {
+		printk(KERN_ERR "%s can't get a page for rx descriptors\n", dev->name);
+		return -EAGAIN;
+	}
+
+	tx_descpage = get_free_page(GFP_KERNEL);
+	if (tx_descpage == 0) {
+		printk(KERN_ERR "%s can't get a page for tx descriptors\n", dev->name);
+		free_page(rx_descpage);
+		return -EAGAIN;
+	}
+
 	dev = init_etherdev(0, sizeof(struct gmac));
 	memset(dev->priv, 0, sizeof(struct gmac));
 
@@ -539,6 +1051,12 @@
 		ioremap(gmac->addrs[0].address, 0x10000);
 	gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
 	dev->irq = gmac->intrs[0].line;
+	gm->dev = dev;
+
+	if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) {
+		gm->pci_bus = gm->pci_devfn = 0xff;
+		printk(KERN_ERR "Can't locate GMAC PCI entry\n");
+	}
 
 	addr = get_property(gmac, "local-mac-address", NULL);
 	if (addr == NULL) {
@@ -552,32 +1070,24 @@
 		dev->dev_addr[i] = addr[i];
 		printk("%c%.2x", (i? ':': ' '), addr[i]);
 	}
-	printk("\n");
-
-	descpage = get_free_page(GFP_KERNEL);
-	if (descpage == 0) {
-		printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
-		return -EAGAIN;
-	}
+	printk(", driver " GMAC_VERSION "\n");
 
-	gm->desc_page = descpage;
-	gm->rxring = (volatile struct gmac_dma_desc *) descpage;
-	gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
+	gm->tx_desc_page = tx_descpage;
+	gm->rx_desc_page = rx_descpage;
+	gm->rxring = (volatile struct gmac_dma_desc *) rx_descpage;
+	gm->txring = (volatile struct gmac_dma_desc *) tx_descpage;
 
 	gm->phy_addr = 0;
+	gm->opened = 0;
 	
 	dev->open = gmac_open;
 	dev->stop = gmac_close;
 	dev->hard_start_xmit = gmac_xmit_start;
 	dev->get_stats = gmac_stats;
+	dev->set_multicast_list = &gmac_set_multicast;
 
 	ether_setup(dev);
 
-	if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
-		printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
-		return -EAGAIN;
-	}
-
 	gmacs = dev;
 
 	return 0;
@@ -585,17 +1095,32 @@
 
 #ifdef MODULE
 
-MODULE_AUTHOR("Paul Mackerras");
+MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");
 MODULE_DESCRIPTION("PowerMac GMAC driver.");
 
-int init_module(void)
+int
+init_module(void)
 {
+	int rc;
+	
 	if (gmacs != NULL)
 		return -EBUSY;
-	return gmac_probe(NULL);
+
+	/* We bump use count during probe since get_free_page can sleep
+	 * which can be a race condition if module is unloaded at this
+	 * point.
+	 */
+	MOD_INC_USE_COUNT;
+
+	rc = gmac_probe(NULL);
+
+	MOD_DEC_USE_COUNT;
+
+	return rc;
 }
 
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
 	struct gmac *gm;
 
@@ -604,9 +1129,9 @@
 		return;
 
 	gm = (struct gmac *) gmacs->priv;
-	free_irq(gmacs->irq, gmac_interrupt);
-	free_page(gm->desc_page);
 	unregister_netdev(gmacs);
+	free_page(gm->rx_desc_page);
+	free_page(gm->tx_desc_page);
 	kfree(gmacs);
 	gmacs = NULL;
 }
diff -urN linux-2.2.17-pre7/drivers/net/gmac.h linux/drivers/net/gmac.h
--- linux-2.2.17-pre7/drivers/net/gmac.h	Mon Dec  3 22:07:14 2001
+++ linux/drivers/net/gmac.h	Mon Dec  3 22:07:25 2001
@@ -3,102 +3,582 @@
  * Apple G4 powermac.
  */
 
-/* Register offsets */
-#define	INTR_STATUS		0x000c
-#define INTR_DISABLE		0x0010
-#define INTR_ACK		0x0014
-#define SW_RESET		0x1010
-#define TXDMA_KICK		0x2000
-#define TXDMA_CONFIG		0x2004
-#define TXDMA_BASE_LOW		0x2008
-#define TXDMA_BASE_HIGH		0x200c
-#define TXDMA_STATE_MACH	0x2028
-#define TXDMA_COMPLETE		0x2100
-#define RXDMA_CONFIG		0x4000
-#define RXDMA_BASE_LOW		0x4004
-#define RXDMA_BASE_HIGH		0x4008
-#define RXDMA_KICK		0x4100
-#define MACPAUSE		0x6008
-#define TXMAC_STATUS		0x6010
-#define TXMAC_CONFIG		0x6030
-#define RXMAC_CONFIG		0x6034
-#define MACCNTL_CONFIG		0x6038
-#define XIF_CONFIG		0x603c
-#define IPG0			0x6040
-#define IPG1			0x6044
-#define IPG2			0x6048
-#define SLOTTIME		0x604c
-#define MINFRAMESIZE		0x6050
-#define MAXFRAMESIZE		0x6054
-#define PASIZE			0x6058
-#define JAMSIZE			0x605c
-#define ATTEMPT_LIMIT		0x6060
-#define MACCNTL_TYPE		0x6064
-#define MAC_ADDR_0		0x6080
-#define MAC_ADDR_1		0x6084
-#define MAC_ADDR_2		0x6088
-#define MAC_ADDR_3		0x608c
-#define MAC_ADDR_4		0x6090
-#define MAC_ADDR_5		0x6094
-#define MAC_ADDR_6		0x6098
-#define MAC_ADDR_7		0x609c
-#define MAC_ADDR_8		0x60a0
-#define MAC_ADDR_FILTER_0	0x60a4
-#define MAC_ADDR_FILTER_1	0x60a8
-#define MAC_ADDR_FILTER_2	0x60ac
-#define MAC_ADDR_FILTER_MASK21	0x60b0
-#define MAC_ADDR_FILTER_MASK0	0x60b4
-#define MAC_HASHTABLE		0x60c0
-#define RANSEED			0x6130
-#define MIFFRAME		0x620c
-#define MIFCONFIG		0x6210
-#define MIFINTMASK		0x6214
-#define MIFSTATUS		0x6218
-#define DATAPATHMODE		0x9050
+
+/* 
+ * GMAC register definitions
+ * 
+ * Note: We encode the register size the same way Apple does. I didn't copy
+ *       Apple's source as-is to avoid licence issues however. That's really
+ *       painful to re-define all those registers ...
+ *       The constants themselves were partially found in OF code, in Sun
+ *       GEM driver and in Apple's Darwin GMAC driver
+ */
+
+#define REG_SZ_8			0x00000000
+#define REG_SZ_16			0x40000000
+#define REG_SZ_32			0x80000000
+#define REG_MASK			0x0FFFFFFF
+
+	/*
+	 * Global registers
+	 */
+
+/* -- 0x0004	RW	Global configuration
+ * d: 0x00000042
+ */
+#define GM_GCONF			(0x0004 | REG_SZ_16)
+#define GM_GCONF_BURST_SZ		0x0001		/* 1: 64 bytes/burst, 0: infinite */
+#define GM_GCONF_TXDMA_LIMIT_MASK	0x003e		/* 5-1: No of 64 bytes transfers */
+#define GM_GCONF_TXDMA_LIMIT_SHIFT	1
+#define GM_GCONF_RXDMA_LIMIT_MASK	0x07c0		/* 10-6: No of 64 bytes transfers */
+#define GM_GCONF_RXDMA_LIMIT_SHIFT	6
 
 /* -- 0x000C	R-C	Global Interrupt status. 
  * d: 0x00000000	bits 0-6 cleared on read (C)
  */
-#define GMAC_IRQ_TX_INT_ME	0x00000001	/* C Frame with INT_ME bit set in fifo */
-#define GMAC_IRQ_TX_ALL		0x00000002	/* C TX descriptor ring empty */
-#define GMAC_IRQ_TX_DONE	0x00000004	/* C moved from host to TX fifo */
-#define GMAC_IRQ_RX_DONE	0x00000010	/* C moved from RX fifo to host */
-#define GMAC_IRQ_RX_NO_BUF	0x00000020	/* C No RX buffer available */
-#define GMAC_IRQ_RX_TAG_ERR	0x00000040	/* C RX tag error */
-
-#define GMAC_IRQ_PCS		0x00002000	/* PCS interrupt ? */
-#define GMAC_IRQ_MAC_TX		0x00004000	/* MAC tx register set */
-#define GMAC_IRQ_MAC_RX		0x00008000	/* MAC rx register set  */
-#define GMAC_IRQ_MAC_CTRL	0x00010000	/* MAC control register set  */
-#define GMAC_IRQ_MIF		0x00020000	/* MIF status register set */
-#define GMAC_IRQ_BUS_ERROR	0x00040000	/* Bus error status register set */
+#define GM_IRQ_STATUS			(0x000c | REG_SZ_32)
+#define GM_IRQ_TX_INT_ME		0x00000001	/* C Frame with INT_ME bit set in fifo */
+#define GM_IRQ_TX_ALL			0x00000002	/* C TX descriptor ring empty */
+#define GM_IRQ_TX_DONE			0x00000004	/* C moved from host to TX fifo */
+#define GM_IRQ_RX_DONE			0x00000010	/* C moved from RX fifo to host */
+#define GM_IRQ_RX_NO_BUF		0x00000020	/* C No RX buffer available */
+#define GM_IRQ_RX_TAG_ERR		0x00000040	/* C RX tag error */
+#define GM_IRQ_PCS			0x00002000	/* PCS interrupt ? */
+#define GM_IRQ_MAC_TX			0x00004000	/* MAC tx register set */
+#define GM_IRQ_MAC_RX			0x00008000	/* MAC rx register set  */
+#define GM_IRQ_MAC_CTRL			0x00010000	/* MAC control register set  */
+#define GM_IRQ_MIF			0x00020000	/* MIF status register set */
+#define GM_IRQ_BUS_ERROR		0x00040000	/* Bus error status register set */
+#define GM_IRQ_TX_COMP			0xfff80000	/* TX completion mask */
+	
+/* -- 0x0010	RW	Interrupt mask. 
+ * d: 0xFFFFFFFF
+ */
+#define GM_IRQ_MASK			(0x0010 | REG_SZ_32)
 
-#define GMAC_IRQ_TX_COMP	0xfff80000	/* TX completion mask */
+/* -- 0x0014	WO	Interrupt ack.
+ * 			Ack. "high" interrupts
+ */
+#define GM_IRQ_ACK			(0x0014 | REG_SZ_32)
 
-/* -- 0x6210	RW	MIF config reg
+/* -- 0x001C	WO	Alias of status register (no auto-clear of "low" interrupts)
+ */
+#define GM_IRQ_ALT_STAT			(0x001C | REG_SZ_32)
+
+/* -- 0x1000	R-C	PCI Error status register
+ */
+#define GM_PCI_ERR_STAT			(0x1000 | REG_SZ_8)
+#define GM_PCI_ERR_BAD_ACK		0x01		/* Bad Ack64 */
+#define GM_PCI_ERR_TIMEOUT		0x02		/* Transaction timeout */
+#define GM_PCI_ERR_OTHER		0x04		/* Any other PCI error */
+	
+/* -- 0x1004	RW	PCI Error mask register
+ * d: 0xFFFFFFFF
+ */
+#define GM_PCI_ERR_MASK			(0x1004 | REG_SZ_8)
+
+/* -- 0x1008	RW	BIF Configuration
+ * d: 0x00000000
+ */
+#define GM_BIF_CFG			(0x1008 | REG_SZ_8)
+#define	GM_BIF_CFG_SLOWCLK		0x01		/* for parity error timing */
+#define	GM_BIF_CFG_HOST_64		0x02		/* 64-bit host */
+#define	GM_BIF_CFG_B64D_DIS		0x04		/* no 64-bit wide data cycle */
+#define	GM_BIF_CFG_M66EN		0x08		/* Read-only: sense if configured for 66MHz */
+	
+/* -- 0x100C	RW	BIF Diagnostic ???
+ */
+#define GM_BIF_DIAG			(0x100C | REG_SZ_32)
+#define GM_BIF_DIAG_BURST_STATE		0x007F0000
+#define GM_BIF_DIAG_STATE_MACH		0xFF000000
+
+/* -- 0x1010	RW	Software reset
+ *			Lower two bits reset TX and RX, both reset whole gmac. They come back
+ *			to 0 when reset is complete.
+ *			bit 2 force RSTOUT# pin when set (PHY reset)
+ */
+#define GM_RESET			(0x1010 | REG_SZ_8)
+#define	GM_RESET_TX			0x01
+#define	GM_RESET_RX			0x02
+#define	GM_RESET_RSTOUT			0x04		/* PHY reset */
+
+
+	/*
+	 * Tx DMA Registers
+	 */
+
+/* -- 0x2000	RW	Tx Kick
+ * d: 0x00000000	Written by the host with the last tx descriptor number +1 to send
+ */
+#define GM_TX_KICK			(0x2000 | REG_SZ_16)
+
+/* -- 0x2004	RW	Tx configuration
+ * d: 0x118010		Controls operation of Tx DMA channel
+ */
+
+#define GM_TX_CONF			(0x2004 | REG_SZ_32)
+#define	GM_TX_CONF_DMA_EN		0x00000001	/* Tx DMA enable */
+#define	GM_TX_CONF_RING_SZ_MASK		0x0000001e	/* Tx desc ring size */
+#define GM_TX_CONF_RING_SZ_SHIFT	1		/* Tx desc ring size shift */
+#define GM_TX_CONF_FIFO_PIO		0x00000020	/* Tx fifo PIO select ??? */
+#define	GM_TX_CONF_FIFO_THR_MASK	0x001ffc00	/* Tx fifo threshold */
+#define GM_TX_CONF_FIFO_THR_SHIFT	10		/* Tx fifo threshold shift */
+#define GM_TX_CONF_FIFO_THR_DEFAULT	0x7ff		/* Tx fifo threshold default */
+#define	GM_TX_CONF_PACED_MODE		0x00100000	/* 1: tx_all irq after last descriptor */
+							/* 0: tx_all irq when tx fifo empty */
+#define	GM_TX_RING_SZ_32		(0 << 1)
+#define	GM_TX_RING_SZ_64		(1 << 1)
+#define	GM_TX_RING_SZ_128		(2 << 1)
+#define	GM_TX_RING_SZ_256		(3 << 1)
+#define	GM_TX_RING_SZ_512		(4 << 1)
+#define	GM_TX_RING_SZ_1024		(5 << 1)
+#define	GM_TX_RING_SZ_2048		(6 << 1)
+#define	GM_TX_RING_SZ_4086		(7 << 1)
+#define	GM_TX_RING_SZ_8192		(8 << 1)
+
+/* -- 0x2008	RW	Tx descriptor ring base low
+ * -- 0x200C	RW	Tx descriptor ring base high
+ *
+ * Base of tx ring, must be 2k aligned
+ */
+#define GM_TX_DESC_LO			(0x2008 | REG_SZ_32)
+#define GM_TX_DESC_HI			(0x200C | REG_SZ_32)
+ 
+/* -- 0x2100	RW	Tx Completion
+ * d: 0x00000000	Written by the gmac with the last tx descriptor number +1 sent
+ */
+#define GM_TX_COMP			(0x2100 | REG_SZ_16)
+
+
+	/*
+	 * Rx DMA registers
+	 */
+
+
+/* -- 0x4000	RW	Rx configuration
+ * d: 0x1000010		Controls operation of Rx DMA channel
+ */
+
+#define GM_RX_CONF			(0x4000 | REG_SZ_32)
+#define	GM_RX_CONF_DMA_EN		0x00000001	/* Rx DMA enable */
+#define	GM_RX_CONF_RING_SZ_MASK		0x0000001e	/* Rx desc ring size */
+#define GM_RX_CONF_RING_SZ_SHIFT	1
+#define	GM_RX_CONF_BATCH_DIS		0x00000020	/* Rx batch disable */
+#define	GM_RX_CONF_FBYTE_OFF_MASK	0x00001c00	/* First byte offset (10-12) */
+#define GM_RX_CONF_FBYTE_OFF_SHIFT	10
+#define	GM_RX_CONF_CHK_START_MASK	0x000FE000	/* Checksum start offset */
+#define GM_RX_CONF_CHK_START_SHIFT	13
+#define	GM_RX_CONF_DMA_THR_MASK		0x07000000	/* Rx DMA threshold */
+#define GM_RX_CONF_DMA_THR_SHIFT	24		/* Rx DMA threshold shift */
+#define GM_RX_CONF_DMA_THR_DEFAULT	1		/* Rx DMA threshold default */
+
+#define	GM_RX_RING_SZ_32		(0 << 1)
+#define	GM_RX_RING_SZ_64		(1 << 1)
+#define	GM_RX_RING_SZ_128		(2 << 1)
+#define	GM_RX_RING_SZ_256		(3 << 1)
+#define	GM_RX_RING_SZ_512		(4 << 1)
+#define	GM_RX_RING_SZ_1024		(5 << 1)
+#define	GM_RX_RING_SZ_2048		(6 << 1)
+#define	GM_RX_RING_SZ_4086		(7 << 1)
+#define	GM_RX_RING_SZ_8192		(8 << 1)
+
+/* -- 0x4004	RW	Rx descriptor ring base low
+ * -- 0x4008	RW	Rx descriptor ring base high
+ *
+ * Base of rx ring
+ */
+#define GM_RX_DESC_LO			(0x4004 | REG_SZ_32)
+#define GM_RX_DESC_HI			(0x4008 | REG_SZ_32)
+
+/* -- 0x4020	RW	Rx pause threshold
+ * d: 0x000000f8	
+ *
+ * Two PAUSE thresholds are used to define when PAUSE flow control frames are
+ * emitted by GEM. The granularity of these thresholds is in 64 byte increments.
+ * XOFF PAUSE frames use the pause_time value pre-programmed in the
+ * Send PAUSE MAC Register.
+ * XON PAUSE frames use a pause_time of 0.
+ */
+#define GM_RX_PTH			(0x4020 | REG_SZ_32)
+			/*
+			 * 0-8: XOFF PAUSE emitted when RX FIFO
+			 * occupancy rises above this value (times 64 bytes)
+			 */
+#define	GM_RX_PTH_OFF_MASK		0x000001ff
+#define GM_RX_PTH_OFF_SHIFT		0
+			/*
+			 * 12-20: XON PAUSE emitted when RX FIFO
+			 * occupancy falls below this value (times 64 bytes)
+			 */
+#define	GM_RX_PTH_ON_MASK		0x001ff000
+#define	GM_RX_PTH_ON_SHIFT		12
+
+#define GM_RX_PTH_UNITS			64
+
+/* -- 0x4100	RW	Rx Kick
+ * d: 0x00000000	Written by the host with the last tx descriptor number +1 to send
+ *					Must be a multiple of 4
+ */
+#define GM_RX_KICK			(0x4100 | REG_SZ_16)
+
+/* -- 0x4104	RW	Rx Completion
+ * d: 0x00000000	Written by the gmac with the last tx descriptor number +1 sent
+ */
+#define GM_RX_COMP			(0x4104 | REG_SZ_16)
+ 
+/* -- 0x4108	RW	Rx Blanking
+ * d: 0x00000000	Written by the gmac with the last tx descriptor number +1 sent
+ *
+ * Defines the values used for receive interrupt blanking.
+ * For INTR_TIME field, every count is 2048 PCI clock time. For 66 Mhz, each
+ * count is about 16 us.
+ */
+#define GM_RX_BLANK			(0x4108 | REG_SZ_32)
+			/*
+			 * 0-8:no.of pkts to be recvd since the last RX_DONE
+			 * interrupt, before a new interrupt
+			 */
+#define	GM_RX_BLANK_INTR_PACKETS_MASK	0x000001ff
+#define	GM_RX_BLANK_INTR_PACKETS_SHIFT	0
+			/*
+			 * 12-19 : no. of clocks to be counted since the last
+			 * RX_DONE interrupt, before a new interrupt
+			 */
+#define	GM_RX_BLANK_INTR_TIME_MASK	0x000ff000
+#define	GM_RX_BLANK_INTR_TIME_SHIFT	12
+
+#define GM_RX_BLANK_UNITS		2048
+
+/* -- 0x4120	RO	Rx fifo size
+ *
+ * This 11-bit RO register indicates the size, in 64-bit multiples, of the
+ * RX FIFO. Software should use it to properly configure the PAUSE thresholds.
+ * The value read is 0x140, indicating a 20kbyte RX FIFO.
+ * -------------------------------------------------------------------------
+ */
+#define GM_RX_FIFO_SIZE			(0x4120 | REG_SZ_16)
+#define GM_RZ_FIFO_SIZE_UNITS		64
+
+
+	/*
+	 * MAC regisers
+	 */
+
+/* -- 0x6000		MAC Tx reset control
+ */
+#define GM_MAC_TX_RESET			(0x6000 | REG_SZ_8)
+#define GM_MAC_TX_RESET_NOW		0x01
+
+/* -- 0x6004		MAC Rx reset control
+ */
+#define GM_MAC_RX_RESET			(0x6004 | REG_SZ_8)
+#define GM_MAC_RX_RESET_NOW		0x01
+
+/* -- 0x6008		Send Pause command register
+ */
+#define GM_MAC_SND_PAUSE		(0x6008 | REG_SZ_32)
+#define GM_MAC_SND_PAUSE_TIME_MASK	0x0000ffff
+#define GM_MAC_SND_PAUSE_TIME_SHIFT	0
+#define GM_MAC_SND_PAUSE_NOW		0x00010000
+#define GM_MAC_SND_PAUSE_DEFAULT	0x00001bf0
+
+/* -- 0x6010		MAC transmit status
+ */
+#define GM_MAC_TX_STATUS		(0x6010 | REG_SZ_16)
+#define GM_MAC_TX_STAT_SENT		0x0001
+#define GM_MAC_TX_STAT_UNDERRUN		0x0002
+#define GM_MAC_TX_STAT_MAX_PKT_ERR	0x0004
+#define GM_MAC_TX_STAT_NORM_COLL_OVF	0x0008
+#define GM_MAC_TX_STAT_EXCS_COLL_OVF	0x0010
+#define GM_MAC_TX_STAT_LATE_COLL_OVF	0x0020
+#define GM_MAC_TX_STAT_FIRS_COLL_OVF	0x0040
+#define GM_MAC_TX_STAT_DEFER_TIMER_OVF	0x0080
+#define GM_MAC_TX_STAT_PEAK_ATTMP_OVF	0x0100
+
+/* -- 0x6014		MAC receive status
+ */
+#define GM_MAC_RX_STATUS		(0x6014 | REG_SZ_16)
+#define GM_MAC_RX_STAT_RECEIVED		0x0001
+#define GM_MAC_RX_STAT_FIFO_OVF		0x0002
+#define GM_MAC_RX_STAT_FRAME_CTR_OVF	0x0004
+#define GM_MAC_RX_STAT_ALIGN_ERR_OVF	0x0008
+#define GM_MAC_RX_STAT_CRC_ERR_OVF	0x0010
+#define GM_MAC_RX_STAT_LEN_ERR_OVF	0x0020
+#define GM_MAC_RX_STAT_CODE_ERR_OVF	0x0040
+
+/* -- 0x6018		MAC control & status
+ */
+#define GM_MAC_CTRLSTAT			(0x6018 | REG_SZ_32)
+#define GM_MAC_CTRLSTAT_PAUSE_RCVD	0x00000001
+#define GM_MAC_CTRLSTAT_PAUSE_STATE	0x00000002
+#define GM_MAC_CTRLSTAT_PAUSE_NOT	0x00000004
+#define GM_MAC_CTRLSTAT_PAUSE_TIM_MASK	0xffff0000
+#define GM_MAC_CTRLSTAT_PAUSE_TIM_SHIFT	16
+
+/* -- 0x6020		MAC Tx mask
+ * 			Same bits as MAC Tx status
  */
+#define GM_MAC_TX_MASK			(0x6020 | REG_SZ_16)
 
-#define	GMAC_MIF_CFGPS			0x00000001	/* PHY Select */
-#define	GMAC_MIF_CFGPE			0x00000002	/* Poll Enable */
-#define	GMAC_MIF_CFGBB			0x00000004	/* Bit Bang Enable */
-#define	GMAC_MIF_CFGPR_MASK		0x000000f8	/* Poll Register address */
-#define	GMAC_MIF_CFGPR_SHIFT		3
-#define	GMAC_MIF_CFGM0			0x00000100	/* MDIO_0 Data / MDIO_0 attached */
-#define	GMAC_MIF_CFGM1			0x00000200	/* MDIO_1 Data / MDIO_1 attached */
-#define	GMAC_MIF_CFGPD_MASK		0x00007c00	/* Poll Device PHY address */
-#define	GMAC_MIF_CFGPD_SHIFT		10
+/* -- 0x6024		MAC Rx mask
+ * 			Same bits as MAC Rx status
+ */
+#define GM_MAC_RX_MASK			(0x6024 | REG_SZ_16)
 
-#define	GMAC_MIF_POLL_DELAY		200
+/* -- 0x6028		MAC Control/Status mask
+ * 			Same bits as MAC control/status low order byte
+ */
+#define GM_MAC_CTRLSTAT_MASK		(0x6024 | REG_SZ_8)
 
-#define	GMAC_INTERNAL_PHYAD		1		/* PHY address for int. transceiver */
-#define	GMAC_EXTERNAL_PHYAD		0		/* PHY address for ext. transceiver */
+/* -- 0x6030		MAC Tx configuration
+ */
+#define GM_MAC_TX_CONFIG		(0x6030 | REG_SZ_16)
+#define GM_MAC_TX_CONF_ENABLE		0x0001
+#define GM_MAC_TX_CONF_IGNORE_CARRIER	0x0002
+#define GM_MAC_TX_CONF_IGNORE_COLL	0x0004
+#define GM_MAC_TX_CONF_ENABLE_IPG0	0x0008
+#define GM_MAC_TX_CONF_DONT_GIVEUP	0x0010
+#define GM_MAC_TX_CONF_DONT_GIVEUP_NLMT	0x0020
+#define GM_MAC_TX_CONF_NO_BACKOFF	0x0040
+#define GM_MAC_TX_CONF_SLOWDOWN		0x0080
+#define GM_MAC_TX_CONF_NO_FCS		0x0100
+#define GM_MAC_TX_CONF_CARRIER_EXT	0x0200
 
+/* -- 0x6034		MAC Rx configuration
+ */
+#define GM_MAC_RX_CONFIG		(0x6034 | REG_SZ_16)
+#define GM_MAC_RX_CONF_ENABLE		0x0001
+#define GM_MAC_RX_CONF_STRIP_PAD	0x0002
+#define GM_MAC_RX_CONF_STIP_FCS		0x0004
+#define GM_MAC_RX_CONF_RX_ALL		0x0008
+#define GM_MAC_RX_CONF_RX_ALL_MULTI	0x0010
+#define GM_MAC_RX_CONF_HASH_ENABLE	0x0020
+#define GM_MAC_RX_CONF_ADDR_FLTR_ENABLE	0x0040
+#define GM_MAC_RX_CONF_PASS_ERROR_FRAM	0x0080
+#define GM_MAC_RX_CONF_CARRIER_EXT	0x0100
+
+/* -- 0x6038		MAC control configuration
+ */
+#define GM_MAC_CTRL_CONFIG		(0x6038 | REG_SZ_8)
+#define GM_MAC_CTRL_CONF_SND_PAUSE_EN	0x01
+#define GM_MAC_CTRL_CONF_RCV_PAUSE_EN	0x02
+#define GM_MAC_CTRL_CONF_PASS_CTRL_FRAM	0x04
+
+/* -- 0x603c		MAC XIF configuration */
+#define GM_MAC_XIF_CONFIG		(0x603c | REG_SZ_8)
+#define GM_MAC_XIF_CONF_TX_MII_OUT_EN	0x01
+#define GM_MAC_XIF_CONF_MII_INT_LOOP	0x02
+#define GM_MAC_XIF_CONF_DISABLE_ECHO	0x04
+#define GM_MAC_XIF_CONF_GMII_MODE	0x08
+#define GM_MAC_XIF_CONF_MII_BUFFER_EN	0x10
+#define GM_MAC_XIF_CONF_LINK_LED	0x20
+#define GM_MAC_XIF_CONF_FULL_DPLX_LED	0x40
+
+/* -- 0x6040		MAC inter-packet GAP 0
+ */
+#define GM_MAC_INTR_PKT_GAP0		(0x6040 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP0_DEFAULT	0x00
+
+/* -- 0x6044		MAC inter-packet GAP 1
+ */
+#define GM_MAC_INTR_PKT_GAP1		(0x6044 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP1_DEFAULT	0x08
+
+/* -- 0x6048		MAC inter-packet GAP 2
+ */
+#define GM_MAC_INTR_PKT_GAP2		(0x6048 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP2_DEFAULT	0x04
+
+/* -- 604c		MAC slot time
+ */
+#define GM_MAC_SLOT_TIME		(0x604C | REG_SZ_16)
+#define GM_MAC_SLOT_TIME_DEFAULT	0x0040
+
+/* -- 6050		MAC minimum frame size
+ */
+#define GM_MAC_MIN_FRAME_SIZE		(0x6050 | REG_SZ_16)
+#define GM_MAC_MIN_FRAME_SIZE_DEFAULT	0x0040
+
+/* -- 6054		MAC maximum frame size
+ */
+#define GM_MAC_MAX_FRAME_SIZE		(0x6054 | REG_SZ_16)
+#define GM_MAC_MAX_FRAME_SIZE_DEFAULT	0x05ee
+#define GM_MAC_MAX_FRAME_SIZE_ALIGN	0x5f0
+
+/* -- 6058		MAC preamble length
+ */
+#define GM_MAC_PREAMBLE_LEN		(0x6058 | REG_SZ_16)
+#define GM_MAC_PREAMBLE_LEN_DEFAULT	0x0007
+
+/* -- 605c		MAC jam size
+ */
+#define GM_MAC_JAM_SIZE			(0x605c | REG_SZ_8)
+#define GM_MAC_JAM_SIZE_DEFAULT		0x04
+
+/* -- 6060		MAC attempt limit
+ */
+#define GM_MAC_ATTEMPT_LIMIT		(0x6060 | REG_SZ_8)
+#define GM_MAC_ATTEMPT_LIMIT_DEFAULT	0x10
+
+/* -- 6064		MAC control type
+ */
+#define GM_MAC_CONTROL_TYPE		(0x6064 | REG_SZ_16)
+#define GM_MAC_CONTROL_TYPE_DEFAULT	0x8808
+
+/* -- 6080		MAC address 15..0
+ * -- 6084		MAC address 16..31
+ * -- 6088		MAC address 32..47
+ */
+#define GM_MAC_ADDR_NORMAL0		(0x6080 | REG_SZ_16)
+#define GM_MAC_ADDR_NORMAL1		(0x6084 | REG_SZ_16)
+#define GM_MAC_ADDR_NORMAL2		(0x6088 | REG_SZ_16)
+
+/* -- 608c		MAC alternate address 15..0
+ * -- 6090		MAC alternate address 16..31
+ * -- 6094		MAC alternate address 32..47
+ */
+#define GM_MAC_ADDR_ALT0		(0x608c | REG_SZ_16)
+#define GM_MAC_ADDR_ALT1		(0x6090 | REG_SZ_16)
+#define GM_MAC_ADDR_ALT2		(0x6094 | REG_SZ_16)
+
+/* -- 6098		MAC control address 15..0
+ * -- 609c		MAC control address 16..31
+ * -- 60a0		MAC control address 32..47
+ */
+#define GM_MAC_ADDR_CTRL0		(0x6098 | REG_SZ_16)
+#define GM_MAC_ADDR_CTRL1		(0x609c | REG_SZ_16)
+#define GM_MAC_ADDR_CTRL2		(0x60a0 | REG_SZ_16)
+
+/* -- 60a4		MAC address filter (0_0)
+ * -- 60a8		MAC address filter (0_1)
+ * -- 60ac		MAC address filter (0_2)
+ */
+#define GM_MAC_ADDR_FILTER0		(0x60a4 | REG_SZ_16)
+#define GM_MAC_ADDR_FILTER1		(0x60a8 | REG_SZ_16)
+#define GM_MAC_ADDR_FILTER2		(0x60ac | REG_SZ_16)
+
+/* -- 60b0		MAC address filter mask 1,2
+ */
+#define GM_MAC_ADDR_FILTER_MASK1_2	(0x60b0 | REG_SZ_8)
+
+/* -- 60b4		MAC address filter mask 0
+ */
+#define GM_MAC_ADDR_FILTER_MASK0	(0x60b4 | REG_SZ_16)
+
+/* -- [60c0 .. 60fc]	MAC hash table
+ */
+#define GM_MAC_ADDR_FILTER_HASH0	(0x60c0 | REG_SZ_16)
+
+/* -- 6100		MAC normal collision counter
+ */
+#define GM_MAC_COLLISION_CTR		(0x6100 | REG_SZ_16)
+
+/* -- 6104		MAC 1st successful collision counter
+ */
+#define GM_MAC_FIRST_COLLISION_CTR	(0x6104 | REG_SZ_16)
+
+/* -- 6108		MAC excess collision counter
+ */
+#define GM_MAC_EXCS_COLLISION_CTR	(0x6108 | REG_SZ_16)
+
+/* -- 610c		MAC late collision counter
+ */
+#define GM_MAC_LATE_COLLISION_CTR	(0x610c | REG_SZ_16)
+
+/* -- 6110		MAC defer timer counter
+ */
+#define GM_MAC_DEFER_TIMER_COUNTER	(0x6110 | REG_SZ_16)
+
+/* -- 6114		MAC peak attempts
+ */
+#define GM_MAC_PEAK_ATTEMPTS		(0x6114 | REG_SZ_16)
+
+/* -- 6118		MAC Rx frame counter
+ */
+#define GM_MAC_RX_FRAME_CTR		(0x6118 | REG_SZ_16)
+
+/* -- 611c		MAC Rx length error counter
+ */
+#define GM_MAC_RX_LEN_ERR_CTR		(0x611c | REG_SZ_16)
+
+/* -- 6120		MAC Rx alignment error counter
+ */
+#define GM_MAC_RX_ALIGN_ERR_CTR		(0x6120 | REG_SZ_16)
+
+/* -- 6124		MAC Rx CRC error counter
+ */
+#define GM_MAC_RX_CRC_ERR_CTR		(0x6124 | REG_SZ_16)
+
+/* -- 6128		MAC Rx code violation error counter
+ */
+#define GM_MAC_RX_CODE_VIOLATION_CTR	(0x6128 | REG_SZ_16)
+
+/* -- 6130		MAC random number seed
+ */
+#define GM_MAC_RANDOM_SEED		(0x6130 | REG_SZ_16)
+
+/* -- 6134		MAC state machine
+ */
+#define GM_MAC_STATE_MACHINE		(0x6134 | REG_SZ_8)
+
+
+	/*
+	 * MIF registers
+	 */
+
+
+/* -- 0x6200	RW	MIF bit bang clock
+ */
+#define GM_MIF_BB_CLOCK			(0x6200 | REG_SZ_8)
+
+/* -- 0x6204	RW	MIF bit bang data
+ */
+#define GM_MIF_BB_DATA			(0x6204 | REG_SZ_8)
+
+/* -- 0x6208	RW	MIF bit bang output enable
+ */
+#define GM_MIF_BB_OUT_ENABLE		(0x6208 | REG_SZ_8)
+
+/* -- 0x620c	RW	MIF frame control & data
+ */
+#define GM_MIF_FRAME_CTL_DATA		(0x620c | REG_SZ_32)
+#define GM_MIF_FRAME_START_MASK		0xc0000000
+#define GM_MIF_FRAME_START_SHIFT	30
+#define GM_MIF_FRAME_OPCODE_MASK	0x30000000
+#define GM_MIF_FRAME_OPCODE_SHIFT	28
+#define GM_MIF_FRAME_PHY_ADDR_MASK	0x0f800000
+#define GM_MIF_FRAME_PHY_ADDR_SHIFT	23
+#define GM_MIF_FRAME_REG_ADDR_MASK	0x007c0000
+#define GM_MIF_FRAME_REG_ADDR_SHIFT	18
+#define GM_MIF_FRAME_TURNAROUND_HI	0x00020000
+#define GM_MIF_FRAME_TURNAROUND_LO	0x00010000
+#define GM_MIF_FRAME_DATA_MASK		0x0000ffff
+#define GM_MIF_FRAME_DATA_SHIFT		0
+
+/* -- 0x6210	RW	MIF config reg
+ */
+#define GM_MIF_CFG			(0x6210 | REG_SZ_16)
+#define	GM_MIF_CFGPS			0x00000001	/* PHY Select */
+#define	GM_MIF_CFGPE			0x00000002	/* Poll Enable */
+#define	GM_MIF_CFGBB			0x00000004	/* Bit Bang Enable */
+#define	GM_MIF_CFGPR_MASK		0x000000f8	/* Poll Register address */
+#define	GM_MIF_CFGPR_SHIFT		3
+#define	GM_MIF_CFGM0			0x00000100	/* MDIO_0 Data / MDIO_0 attached */
+#define	GM_MIF_CFGM1			0x00000200	/* MDIO_1 Data / MDIO_1 attached */
+#define	GM_MIF_CFGPD_MASK		0x00007c00	/* Poll Device PHY address */
+#define	GM_MIF_CFGPD_SHIFT		10
+
+#define	GM_MIF_POLL_DELAY		200
+
+#define	GM_INTERNAL_PHYAD		1		/* PHY address for int. transceiver */
+#define	GM_EXTERNAL_PHYAD		0		/* PHY address for ext. transceiver */
 
 /* -- 0x6214	RW	MIF interrupt mask reg
  *			same as basic/status Register
  */
+#define GM_MIF_IRQ_MASK			(0x6214 | REG_SZ_16)
 
-/* -- 0x6214	RW	MIF basic/status reg
+/* -- 0x6218	RW	MIF basic/status reg
  *			The Basic portion of this register indicates the last
  *			value of the register read indicated in the POLL REG field
  *			of the Configuration Register.
@@ -107,7 +587,304 @@
  *			terms of the bit(s) that need to be masked for generating
  *			interrupt on the MIF Interrupt Bit of the Global Status Rgister.
  */
+#define GM_MIF_STATUS			(0x6218 | REG_SZ_32)
+
+#define	GM_MIF_STATUS_MASK		0x0000ffff	/* 0-15 : Status */
+#define	GM_MIF_BASIC_MASK		0xffff0000	/* 16-31 : Basic register */
+
+	/*
+	 * PCS link registers
+	 */
 
-#define	GMAC_MIF_STATUS			0x0000ffff	/* 0-15 : Status */
-#define	GMAC_MIF_BASIC			0xffff0000	/* 16-31 : Basic register */
+/* -- 0x9000	RW	PCS mii control reg
+ */
+#define GM_PCS_CONTROL			(0x9000 | REG_SZ_16)
+
+/* -- 0x9004	RW	PCS mii status reg
+ */
+#define GM_PCS_STATUS			(0x9004 | REG_SZ_16)
+
+/* -- 0x9008	RW	PCS mii advertisement
+ */
+#define GM_PCS_ADVERTISEMENT		(0x9008 | REG_SZ_16)
+
+/* -- 0x900c	RW	PCS mii LP ability
+ */
+#define GM_PCS_ABILITY			(0x900c | REG_SZ_16)
+
+/* -- 0x9010	RW	PCS config
+ */
+#define GM_PCS_CONFIG			(0x9010 | REG_SZ_8)
+
+/* -- 0x9014	RW	PCS state machine
+ */
+#define GM_PCS_STATE_MACHINE		(0x9014 | REG_SZ_32)
+
+/* -- 0x9018	RW	PCS interrupt status
+ */
+#define GM_PCS_IRQ_STATUS		(0x9018 | REG_SZ_8)
+
+/* -- 0x9050	RW	PCS datapath mode
+ */
+#define GM_PCS_DATAPATH_MODE		(0x9050 | REG_SZ_8)
+#define GM_PCS_DATAPATH_INTERNAL	0x01	/* Internal serial link */
+#define GM_PCS_DATAPATH_SERDES		0x02	/* 10-bit Serdes interface */
+#define GM_PCS_DATAPATH_MII		0x04	/* Select mii/gmii mode */
+#define GM_PCS_DATAPATH_GMII_OUT	0x08	/* serial mode only, copy data to gmii */
+
+/* -- 0x9054	RW	PCS serdes control
+ */
+#define GM_PCS_SERDES_CTRL		(0x9054 | REG_SZ_8)
+
+/* -- 0x9058	RW	PCS serdes output select
+ */
+#define GM_PCS_SERDES_SELECT		(0x9058 | REG_SZ_8)
+
+/* -- 0x905c	RW	PCS serdes state
+ */
+#define GM_PCS_SERDES_STATE		(0x905c | REG_SZ_8)
+
+
+	/*
+	 * PHY registers
+	 */
+
+/*
+ * Standard PHY registers (from de4x5.h)
+ */
+#define MII_CR       0x00          /* MII Management Control Register */
+#define MII_SR       0x01          /* MII Management Status Register */
+#define MII_ID0      0x02          /* PHY Identifier Register 0 */
+#define MII_ID1      0x03          /* PHY Identifier Register 1 */
+#define MII_ANA      0x04          /* Auto Negotiation Advertisement */
+#define MII_ANLPA    0x05          /* Auto Negotiation Link Partner Ability */
+#define MII_ANE      0x06          /* Auto Negotiation Expansion */
+#define MII_ANP      0x07          /* Auto Negotiation Next Page TX */
+
+/*
+** MII Management Control Register
+*/
+#define MII_CR_RST  0x8000         /* RESET the PHY chip */
+#define MII_CR_LPBK 0x4000         /* Loopback enable */
+#define MII_CR_SPD  0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_10   0x0000         /* Set 10Mb/s */
+#define MII_CR_100  0x2000         /* Set 100Mb/s */
+#define MII_CR_ASSE 0x1000         /* Auto Speed Select Enable */
+#define MII_CR_PD   0x0800         /* Power Down */
+#define MII_CR_ISOL 0x0400         /* Isolate Mode */
+#define MII_CR_RAN  0x0200         /* Restart Auto Negotiation */
+#define MII_CR_FDM  0x0100         /* Full Duplex Mode */
+#define MII_CR_CTE  0x0080         /* Collision Test Enable */
+
+/*
+** MII Management Status Register
+*/
+#define MII_SR_T4C  0x8000         /* 100BASE-T4 capable */
+#define MII_SR_TXFD 0x4000         /* 100BASE-TX Full Duplex capable */
+#define MII_SR_TXHD 0x2000         /* 100BASE-TX Half Duplex capable */
+#define MII_SR_TFD  0x1000         /* 10BASE-T Full Duplex capable */
+#define MII_SR_THD  0x0800         /* 10BASE-T Half Duplex capable */
+#define MII_SR_ASSC 0x0020         /* Auto Speed Selection Complete*/
+#define MII_SR_RFD  0x0010         /* Remote Fault Detected */
+#define MII_SR_ANC  0x0008         /* Auto Negotiation capable */
+#define MII_SR_LKS  0x0004         /* Link Status */
+#define MII_SR_JABD 0x0002         /* Jabber Detect */
+#define MII_SR_XC   0x0001         /* Extended Capabilities */
+
+/*
+** MII Management Auto Negotiation Advertisement Register
+*/
+#define MII_ANA_TAF  0x03e0        /* Technology Ability Field */
+#define MII_ANA_T4AM 0x0200        /* T4 Technology Ability Mask */
+#define MII_ANA_TXAM 0x0180        /* TX Technology Ability Mask */
+#define MII_ANA_FDAM 0x0140        /* Full Duplex Technology Ability Mask */
+#define MII_ANA_HDAM 0x02a0        /* Half Duplex Technology Ability Mask */
+#define MII_ANA_100M 0x0380        /* 100Mb Technology Ability Mask */
+#define MII_ANA_10M  0x0060        /* 10Mb Technology Ability Mask */
+#define MII_ANA_CSMA 0x0001        /* CSMA-CD Capable */
+
+/*
+** MII Management Auto Negotiation Remote End Register
+*/
+#define MII_ANLPA_NP   0x8000      /* Next Page (Enable) */
+#define MII_ANLPA_ACK  0x4000      /* Remote Acknowledge */
+#define MII_ANLPA_RF   0x2000      /* Remote Fault */
+#define MII_ANLPA_TAF  0x03e0      /* Technology Ability Field */
+#define MII_ANLPA_T4AM 0x0200      /* T4 Technology Ability Mask */
+#define MII_ANLPA_TXAM 0x0180      /* TX Technology Ability Mask */
+#define MII_ANLPA_FDAM 0x0140      /* Full Duplex Technology Ability Mask */
+#define MII_ANLPA_HDAM 0x02a0      /* Half Duplex Technology Ability Mask */
+#define MII_ANLPA_100M 0x0380      /* 100Mb Technology Ability Mask */
+#define MII_ANLPA_10M  0x0060      /* 10Mb Technology Ability Mask */
+#define MII_ANLPA_CSMA 0x0001      /* CSMA-CD Capable */
+#define MII_ANLPA_PAUS 0x0400 
+
+/*
+ * Model-specific PHY registers
+ *
+ * Note: Only the BCM5201 is described here for now. I'll add the 5400 once
+ *       I see a machine using it in real world.
+ */
+
+/* Supported PHYs (phy_type field ) */
+#define PHY_B5400	5400
+#define PHY_B5201	5201
+#define PHY_UNKNOWN	0
+
+/* Identification (for multi-PHY) */
+#define MII_BCM5201_OUI                         0x001018
+#define MII_BCM5201_MODEL                       0x21
+#define MII_BCM5201_REV                         0x01
+#define MII_BCM5201_ID                          ((MII_BCM5201_OUI << 10) | (MII_BCM5201_MODEL << 4))
+#define MII_BCM5201_MASK                        0xfffffff0
+#define MII_BCM5400_OUI                         0x000818
+#define MII_BCM5400_MODEL                       0x04
+#define MII_BCM5400_REV                         0x01
+#define MII_BCM5400_ID                          ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4))
+#define MII_BCM5400_MASK                        0xfffffff0
+
+/* BCM5201 AUX STATUS register */
+#define MII_BCM5201_AUXCTLSTATUS		0x18
+#define MII_BCM5201_AUXCTLSTATUS_DUPLEX		0x0001
+#define MII_BCM5201_AUXCTLSTATUS_SPEED		0x0002
+
+/* MII BCM5201 MULTIPHY interrupt register */
+#define MII_BCM5201_INTERRUPT			0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE		0x4000
+
+#define MII_BCM5201_AUXMODE2			0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER		0x0008
+
+#define MII_BCM5201_MULTIPHY                    0x1E
+
+/* MII BCM5201 MULTIPHY register bits */
+#define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+
+
+
+	/*
+	 * DMA descriptors
+	 */
+
+
+/* 
+ * Descriptor counts and buffer sizes
+ */
+#define NTX			64		/* must be power of 2 */
+#define NTX_CONF		GM_TX_RING_SZ_64
+#define NRX			64		/* must be power of 2 */
+#define NRX_CONF		GM_RX_RING_SZ_64
+#define RX_COPY_THRESHOLD	256
+#define GMAC_BUFFER_ALIGN	32		/* Align on a cache line */
+#define RX_BUF_ALLOC_SIZE	(ETH_FRAME_LEN + GMAC_BUFFER_ALIGN + 2)
+#define RX_OFFSET		2
+
+/*
+ * Definitions of Rx and Tx descriptors
+ */
+
+struct gmac_dma_desc {
+	unsigned int	size;		/* data size and OWN bit */
+	unsigned int	flags;		/* flags */
+	unsigned int	lo_addr;	/* phys addr, low 32 bits */
+	unsigned int	hi_addr;
+};
+
+/*
+ * Rx bits
+ */
+ 
+/* Bits in size */
+#define RX_SZ_OWN		0x80000000	/* 1 = owned by chip */
+#define RX_SZ_MASK		0x7FFF0000
+#define RX_SZ_SHIFT		16
+#define RX_SZ_CKSUM_MASK	0x0000FFFF
+
+/* Bits in flags */
+#define RX_FL_CRC_ERROR		0x40000000
+#define RX_FL_ALT_ADDR		0x20000000	/* Packet rcv. from alt MAC address */
+
+/* 
+ * Tx bits
+ */
+
+/* Bits in size */
+#define TX_SZ_MASK		0x00007FFF
+#define TX_SZ_CRC_MASK		0x00FF8000
+#define TX_SZ_CRC_STUFF		0x1F000000
+#define TX_SZ_CRC_ENABLE	0x20000000
+#define TX_SZ_EOP		0x40000000
+#define TX_SZ_SOP		0x80000000
+/* Bits in flags */
+#define TX_FL_INTERRUPT		0x00000001
+#define TX_FL_NO_CRC		0x00000002
+
+	/*
+	 * Other stuffs
+	 */
+	 
+struct gmac {
+	volatile unsigned int		*regs;	/* hardware registers, virtual addr */
+	volatile unsigned int		*sysregs;
+	struct device			*dev;
+	unsigned long			tx_desc_page;	/* page for DMA descriptors */
+	unsigned long			rx_desc_page;	/* page for DMA descriptors */
+	volatile struct			gmac_dma_desc *rxring;
+	struct sk_buff			*rx_buff[NRX];
+	int				next_rx;
+	volatile struct	gmac_dma_desc	*txring;
+	struct sk_buff			*tx_buff[NTX];
+	int				next_tx;
+	int				tx_gone;
+	int				phy_addr;
+	unsigned int			phy_id;
+	int				phy_type;
+	int				phy_status;	/* Cached PHY status */
+	int				full_duplex;	/* Current set to full duplex */
+	int				promisc;
+	struct net_device_stats		stats;
+	u8				pci_bus;
+	u8				pci_devfn;
+	int				opened;
+};
+
+
+/* Register access macros. We hope the preprocessor will be smart enough
+ * to optimize them into one single access instruction
+ */
+#define GM_OUT(reg, v)		(((reg) & REG_SZ_32) ? out_le32(gm->regs + \
+					(((reg) & REG_MASK)>>2), (v))  \
+				: (((reg) & REG_SZ_16) ? out_le16((volatile u16 *) \
+					(gm->regs + (((reg) & REG_MASK)>>2)), (v))  \
+				: out_8((volatile u8 *)(gm->regs + \
+					(((reg) & REG_MASK)>>2)), (v))))
+#define GM_IN(reg)		(((reg) & REG_SZ_32) ? in_le32(gm->regs + \
+					(((reg) & REG_MASK)>>2))  \
+				: (((reg) & REG_SZ_16) ? in_le16((volatile u16 *) \
+					(gm->regs + (((reg) & REG_MASK)>>2)))  \
+				: in_8((volatile u8 *)(gm->regs + \
+					(((reg) & REG_MASK)>>2)))))
+#define GM_BIS(r, v)		GM_OUT((r), GM_IN(r) | (v))
+#define GM_BIC(r, v)		GM_OUT((r), GM_IN(r) & ~(v))
+
+/* Wrapper to alloc_skb to test various alignements */
+#define GMAC_ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + GMAC_BUFFER_ALIGN - 1) & \
+        ~(GMAC_BUFFER_ALIGN - 1)) - (unsigned long)(addr))
+        
+static inline struct sk_buff *
+gmac_alloc_skb(unsigned int length, int gfp_flags)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(length + GMAC_BUFFER_ALIGN, gfp_flags);
+	if(skb) {
+		int offset = GMAC_ALIGNED_RX_SKB_ADDR(skb->data);
+
+		if(offset)
+			skb_reserve(skb, offset);
+	}
+	return skb;
+}
 
diff -urN linux-2.2.17-pre7/drivers/net/mace.c linux/drivers/net/mace.c
--- linux-2.2.17-pre7/drivers/net/mace.c	Mon Dec  3 22:07:14 2001
+++ linux/drivers/net/mace.c	Mon Dec  3 22:07:25 2001
@@ -926,9 +926,9 @@
     struct mace_data *mp = (struct mace_data *) mace_devs->priv;
     unregister_netdev(mace_devs);
 
-    free_irq(mace_devs->irq, mace_interrupt);
-    free_irq(mp->tx_dma_intr, mace_txdma_intr);
-    free_irq(mp->rx_dma_intr, mace_rxdma_intr);
+    free_irq(mace_devs->irq, dev);
+    free_irq(mp->tx_dma_intr, dev);
+    free_irq(mp->rx_dma_intr, dev);
 
     kfree(mace_devs);
     mace_devs = NULL;
diff -urN linux-2.2.17-pre7/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c
--- linux-2.2.17-pre7/drivers/scsi/mac53c94.c	Wed Aug 25 17:29:48 1999
+++ linux/drivers/scsi/mac53c94.c	Mon Dec  3 22:07:25 2001
@@ -7,6 +7,7 @@
  * Paul Mackerras, August 1996.
  * Copyright (C) 1996 Paul Mackerras.
  */
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/types.h>
@@ -542,3 +543,9 @@
 		return 0;
 	}
 }
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = SCSI_MAC53C94;
+
+#include "scsi_module.c"
+#endif /* MODULE */
diff -urN linux-2.2.17-pre7/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- linux-2.2.17-pre7/drivers/scsi/mesh.c	Tue Jan  4 10:12:20 2000
+++ linux/drivers/scsi/mesh.c	Mon Dec  3 22:07:25 2001
@@ -8,6 +8,7 @@
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/types.h>
@@ -1910,6 +1911,12 @@
 		return 0;
 	}
 }
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = SCSI_MESH;
+
+#include "scsi_module.c"
+#endif /* MODULE */
 
 #ifdef MESH_DBG
 static inline u32 readtb(void)
diff -urN linux-2.2.17-pre7/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- linux-2.2.17-pre7/drivers/scsi/sym53c8xx.c	Mon Dec  3 22:07:14 2001
+++ linux/drivers/scsi/sym53c8xx.c	Mon Dec  3 22:07:25 2001
@@ -9021,7 +9021,7 @@
 **	code will get more complex later).
 */
 
-#if BITS_PER_LONG > 32
+#ifdef SCSI_NCR_USE_64BIT_DAC
 #define SCATTER_ONE(data, badd, len)					\
 	(data)->addr = cpu_to_scr(badd);				\
 	(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len);
diff -urN linux-2.2.17-pre7/fs/buffer.c linux/fs/buffer.c
--- linux-2.2.17-pre7/fs/buffer.c	Mon Dec  3 22:07:14 2001
+++ linux/fs/buffer.c	Mon Dec  3 22:07:26 2001
@@ -1502,6 +1502,7 @@
 int try_to_free_buffers(struct page * page_map, int wait)
 {
 	struct buffer_head * tmp, * bh = page_map->buffers;
+	int too_many;
 
 	tmp = bh;
 	do {
@@ -1530,14 +1531,25 @@
 	return 1;
 
  busy:
-	if (!sync_page_buffers(bh, wait))
+	too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
+
+	if (!sync_page_buffers(bh, wait)) {
+
+		/* If a high percentage of the buffers are dirty, 
+		 * wake kflushd 
+		 */
+		if (nr_buffers_type[BUF_DIRTY] > too_many)
+			wakeup_bdflush(0);
+			
 		/*
 		 * We can jump after the busy check because
 		 * we rely on the kernel lock.
 		 */
 		goto succeed;
+	}
 
-	wakeup_bdflush(0);
+	if(nr_buffers_type[BUF_DIRTY] > too_many)
+		wakeup_bdflush(0);
 	return 0;
 }
 
diff -urN linux-2.2.17-pre7/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- linux-2.2.17-pre7/include/asm-ppc/processor.h	Mon Dec  3 22:07:15 2001
+++ linux/include/asm-ppc/processor.h	Mon Dec  3 22:07:26 2001
@@ -4,7 +4,6 @@
 #include <linux/config.h>
 
 #include <asm/ptrace.h>
-#include <asm/residual.h>
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_VEC		(1<<25)		/* Enable Altivec */
diff -urN linux-2.2.17-pre7/include/asm-ppc/residual.h linux/include/asm-ppc/residual.h
--- linux-2.2.17-pre7/include/asm-ppc/residual.h	Tue Aug  4 16:06:36 1998
+++ linux/include/asm-ppc/residual.h	Mon Dec  3 22:07:26 2001
@@ -25,7 +25,7 @@
 /*               Public structures...                                         */
 /*----------------------------------------------------------------------------*/
 
-#include "pnp.h"
+#include <asm/pnp.h>
 
 typedef enum _L1CACHE_TYPE {
   NoneCAC = 0,
diff -urN linux-2.2.17-pre7/include/asm-ppc/time.h linux/include/asm-ppc/time.h
--- linux-2.2.17-pre7/include/asm-ppc/time.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/time.h	Mon Dec  3 22:07:26 2001
@@ -0,0 +1,34 @@
+/*
+ * $Id: time.h,v 1.11.2.1 1999/08/27 04:20:35 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/mc146818rtc.h>
+
+/* time.c */
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
+			    unsigned int, unsigned int, unsigned int);
+extern void to_tm(int tim, struct rtc_time * tm);
+extern time_t last_rtc_update;
+
+int via_calibrate_decr(void);
+
+/* Accessor functions for the decrementer register. */
+static __inline__ unsigned int get_dec(void)
+{
+	unsigned int ret;
+
+	asm volatile("mfspr %0,22" : "=r" (ret) :);
+	return ret;
+}
+
+static __inline__ void set_dec(unsigned int val)
+{
+	asm volatile("mtspr 22,%0" : : "r" (val));
+}
diff -urN linux-2.2.17-pre7/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.2.17-pre7/mm/vmscan.c	Mon Dec  3 22:07:15 2001
+++ linux/mm/vmscan.c	Mon Dec  3 22:07:26 2001
@@ -419,7 +419,7 @@
 done:
 	unlock_kernel();
 
-	if (priority < 0)
+	if (!ret)
 		printk("VM: do_try_to_free_pages failed for %s...\n",
 				current->comm);
 	/* Return success if we freed a page. */
