v4.19.13 snapshot.
diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig
new file mode 100644
index 0000000..3107129
--- /dev/null
+++ b/drivers/net/ethernet/apple/Kconfig
@@ -0,0 +1,62 @@
+#
+# Apple device configuration
+#
+
+config NET_VENDOR_APPLE
+	bool "Apple devices"
+	default y
+	depends on (PPC_PMAC && PPC32) || MAC
+	---help---
+	  If you have a network (Ethernet) card belonging to this class, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about IBM devices. If you say Y, you will be asked for
+	  your specific card in the following questions.
+
+if NET_VENDOR_APPLE
+
+config MACE
+	tristate "MACE (Power Mac ethernet) support"
+	depends on PPC_PMAC && PPC32
+	select CRC32
+	---help---
+	  Power Macintoshes and clones with Ethernet built-in on the
+	  motherboard will usually use a MACE (Medium Access Control for
+	  Ethernet) interface. Say Y to include support for the MACE chip.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mace.
+
+config MACE_AAUI_PORT
+	bool "Use AAUI port instead of TP by default"
+	depends on MACE
+	---help---
+	  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.
+	  The driver will default to AAUI on ANS anyway, and if you use it as
+	  a module, you can provide the port_aaui=0|1 to force the driver.
+
+config BMAC
+	tristate "BMAC (G3 ethernet) support"
+	depends on PPC_PMAC && PPC32
+	select CRC32
+	---help---
+	  Say Y for support of BMAC Ethernet interfaces. These are used on G3
+	  computers.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bmac.
+
+config MACMACE
+	tristate "Macintosh (AV) onboard MACE ethernet"
+	depends on MAC
+	select CRC32
+	---help---
+	  Support for the onboard AMD 79C940 MACE Ethernet controller used in
+	  the 660AV and 840AV Macintosh.  If you have one of these Macintoshes
+	  say Y here.
+
+endif # NET_VENDOR_APPLE
diff --git a/drivers/net/ethernet/apple/Makefile b/drivers/net/ethernet/apple/Makefile
new file mode 100644
index 0000000..86eaa17
--- /dev/null
+++ b/drivers/net/ethernet/apple/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Apple network device drivers.
+#
+
+obj-$(CONFIG_MACE) += mace.o
+obj-$(CONFIG_BMAC) += bmac.o
+obj-$(CONFIG_MACMACE) += macmace.o
diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c
new file mode 100644
index 0000000..6a8e256
--- /dev/null
+++ b/drivers/net/ethernet/apple/bmac.c
@@ -0,0 +1,1671 @@
+/*
+ * Network device driver for the BMAC ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
+ * dynamic procfs inode.
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+#include <linux/crc32poly.h>
+#include <linux/bitrev.h>
+#include <linux/ethtool.h>
+#include <linux/slab.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/macio.h>
+#include <asm/irq.h>
+
+#include "bmac.h"
+
+#define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x)	trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+/* switch to use multicast code lifted from sunhme driver */
+#define SUNHME_MULTICAST
+
+#define N_RX_RING	64
+#define N_TX_RING	32
+#define MAX_TX_ACTIVE	1
+#define ETHERCRC	4
+#define ETHERMINPACKET	64
+#define ETHERMTU	1500
+#define RX_BUFLEN	(ETHERMTU + 14 + ETHERCRC + 2)
+#define TX_TIMEOUT	HZ	/* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR	0x80
+
+#define XXDEBUG(args)
+
+struct bmac_data {
+	/* volatile struct bmac *bmac; */
+	struct sk_buff_head *queue;
+	volatile struct dbdma_regs __iomem *tx_dma;
+	int tx_dma_intr;
+	volatile struct dbdma_regs __iomem *rx_dma;
+	int rx_dma_intr;
+	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
+	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
+	struct macio_dev *mdev;
+	int is_bmac_plus;
+	struct sk_buff *rx_bufs[N_RX_RING];
+	int rx_fill;
+	int rx_empty;
+	struct sk_buff *tx_bufs[N_TX_RING];
+	int tx_fill;
+	int tx_empty;
+	unsigned char tx_fullup;
+	struct timer_list tx_timeout;
+	int timeout_active;
+	int sleeping;
+	int opened;
+	unsigned short hash_use_count[64];
+	unsigned short hash_table_mask[4];
+	spinlock_t lock;
+};
+
+#if 0 /* Move that to ethtool */
+
+typedef struct bmac_reg_entry {
+	char *name;
+	unsigned short reg_offset;
+} bmac_reg_entry_t;
+
+#define N_REG_ENTRIES 31
+
+static bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
+	{"MEMADD", MEMADD},
+	{"MEMDATAHI", MEMDATAHI},
+	{"MEMDATALO", MEMDATALO},
+	{"TXPNTR", TXPNTR},
+	{"RXPNTR", RXPNTR},
+	{"IPG1", IPG1},
+	{"IPG2", IPG2},
+	{"ALIMIT", ALIMIT},
+	{"SLOT", SLOT},
+	{"PALEN", PALEN},
+	{"PAPAT", PAPAT},
+	{"TXSFD", TXSFD},
+	{"JAM", JAM},
+	{"TXCFG", TXCFG},
+	{"TXMAX", TXMAX},
+	{"TXMIN", TXMIN},
+	{"PAREG", PAREG},
+	{"DCNT", DCNT},
+	{"NCCNT", NCCNT},
+	{"NTCNT", NTCNT},
+	{"EXCNT", EXCNT},
+	{"LTCNT", LTCNT},
+	{"TXSM", TXSM},
+	{"RXCFG", RXCFG},
+	{"RXMAX", RXMAX},
+	{"RXMIN", RXMIN},
+	{"FRCNT", FRCNT},
+	{"AECNT", AECNT},
+	{"FECNT", FECNT},
+	{"RXSM", RXSM},
+	{"RXCV", RXCV}
+};
+
+#endif
+
+static unsigned char *bmac_emergency_rxbuf;
+
+/*
+ * Number of bytes of private data per BMAC: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES	(sizeof(struct bmac_data) \
+	+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+	+ sizeof(struct sk_buff_head))
+
+static int bmac_open(struct net_device *dev);
+static int bmac_close(struct net_device *dev);
+static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
+static void bmac_set_multicast(struct net_device *dev);
+static void bmac_reset_and_enable(struct net_device *dev);
+static void bmac_start_chip(struct net_device *dev);
+static void bmac_init_chip(struct net_device *dev);
+static void bmac_init_registers(struct net_device *dev);
+static void bmac_enable_and_reset_chip(struct net_device *dev);
+static int bmac_set_address(struct net_device *dev, void *addr);
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id);
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id);
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id);
+static void bmac_set_timeout(struct net_device *dev);
+static void bmac_tx_timeout(struct timer_list *t);
+static netdev_tx_t bmac_output(struct sk_buff *skb, struct net_device *dev);
+static void bmac_start(struct net_device *dev);
+
+#define	DBDMA_SET(x)	( ((x) | (x) << 16) )
+#define	DBDMA_CLEAR(x)	( (x) << 16)
+
+static inline void
+dbdma_st32(volatile __u32 __iomem *a, unsigned long x)
+{
+	__asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+}
+
+static inline unsigned long
+dbdma_ld32(volatile __u32 __iomem *a)
+{
+	__u32 swap;
+	__asm__ volatile ("lwbrx %0,0,%1" :  "=r" (swap) : "r" (a));
+	return swap;
+}
+
+static void
+dbdma_continue(volatile struct dbdma_regs __iomem *dmap)
+{
+	dbdma_st32(&dmap->control,
+		   DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
+	eieio();
+}
+
+static void
+dbdma_reset(volatile struct dbdma_regs __iomem *dmap)
+{
+	dbdma_st32(&dmap->control,
+		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
+	eieio();
+	while (dbdma_ld32(&dmap->status) & RUN)
+		eieio();
+}
+
+static void
+dbdma_setcmd(volatile struct dbdma_cmd *cp,
+	     unsigned short cmd, unsigned count, unsigned long addr,
+	     unsigned long cmd_dep)
+{
+	out_le16(&cp->command, cmd);
+	out_le16(&cp->req_count, count);
+	out_le32(&cp->phy_addr, addr);
+	out_le32(&cp->cmd_dep, cmd_dep);
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->res_count, 0);
+}
+
+static inline
+void bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data )
+{
+	out_le16((void __iomem *)dev->base_addr + reg_offset, data);
+}
+
+
+static inline
+unsigned short bmread(struct net_device *dev, unsigned long reg_offset )
+{
+	return in_le16((void __iomem *)dev->base_addr + reg_offset);
+}
+
+static void
+bmac_enable_and_reset_chip(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+
+	if (rd)
+		dbdma_reset(rd);
+	if (td)
+		dbdma_reset(td);
+
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1);
+}
+
+#define MIFDELAY	udelay(10)
+
+static unsigned int
+bmac_mif_readbits(struct net_device *dev, int nb)
+{
+	unsigned int val = 0;
+
+	while (--nb >= 0) {
+		bmwrite(dev, MIFCSR, 0);
+		MIFDELAY;
+		if (bmread(dev, MIFCSR) & 8)
+			val |= 1 << nb;
+		bmwrite(dev, MIFCSR, 1);
+		MIFDELAY;
+	}
+	bmwrite(dev, MIFCSR, 0);
+	MIFDELAY;
+	bmwrite(dev, MIFCSR, 1);
+	MIFDELAY;
+	return val;
+}
+
+static void
+bmac_mif_writebits(struct net_device *dev, unsigned int val, int nb)
+{
+	int b;
+
+	while (--nb >= 0) {
+		b = (val & (1 << nb))? 6: 4;
+		bmwrite(dev, MIFCSR, b);
+		MIFDELAY;
+		bmwrite(dev, MIFCSR, b|1);
+		MIFDELAY;
+	}
+}
+
+static unsigned int
+bmac_mif_read(struct net_device *dev, unsigned int addr)
+{
+	unsigned int val;
+
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	bmac_mif_writebits(dev, ~0U, 32);
+	bmac_mif_writebits(dev, 6, 4);
+	bmac_mif_writebits(dev, addr, 10);
+	bmwrite(dev, MIFCSR, 2);
+	MIFDELAY;
+	bmwrite(dev, MIFCSR, 1);
+	MIFDELAY;
+	val = bmac_mif_readbits(dev, 17);
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	return val;
+}
+
+static void
+bmac_mif_write(struct net_device *dev, unsigned int addr, unsigned int val)
+{
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	bmac_mif_writebits(dev, ~0U, 32);
+	bmac_mif_writebits(dev, 5, 4);
+	bmac_mif_writebits(dev, addr, 10);
+	bmac_mif_writebits(dev, 2, 2);
+	bmac_mif_writebits(dev, val, 16);
+	bmac_mif_writebits(dev, 3, 2);
+}
+
+static void
+bmac_init_registers(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile unsigned short regValue;
+	unsigned short *pWord16;
+	int i;
+
+	/* XXDEBUG(("bmac: enter init_registers\n")); */
+
+	bmwrite(dev, RXRST, RxResetValue);
+	bmwrite(dev, TXRST, TxResetBit);
+
+	i = 100;
+	do {
+		--i;
+		udelay(10000);
+		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
+	} while ((regValue & TxResetBit) && i > 0);
+
+	if (!bp->is_bmac_plus) {
+		regValue = bmread(dev, XCVRIF);
+		regValue |= ClkBit | SerialMode | COLActiveLow;
+		bmwrite(dev, XCVRIF, regValue);
+		udelay(10000);
+	}
+
+	bmwrite(dev, RSEED, (unsigned short)0x1968);
+
+	regValue = bmread(dev, XIFC);
+	regValue |= TxOutputEnable;
+	bmwrite(dev, XIFC, regValue);
+
+	bmread(dev, PAREG);
+
+	/* set collision counters to 0 */
+	bmwrite(dev, NCCNT, 0);
+	bmwrite(dev, NTCNT, 0);
+	bmwrite(dev, EXCNT, 0);
+	bmwrite(dev, LTCNT, 0);
+
+	/* set rx counters to 0 */
+	bmwrite(dev, FRCNT, 0);
+	bmwrite(dev, LECNT, 0);
+	bmwrite(dev, AECNT, 0);
+	bmwrite(dev, FECNT, 0);
+	bmwrite(dev, RXCV, 0);
+
+	/* set tx fifo information */
+	bmwrite(dev, TXTH, 4);	/* 4 octets before tx starts */
+
+	bmwrite(dev, TXFIFOCSR, 0);	/* first disable txFIFO */
+	bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
+
+	/* set rx fifo information */
+	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
+	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+
+	//bmwrite(dev, TXCFG, TxMACEnable);	       	/* TxNeverGiveUp maybe later */
+	bmread(dev, STATUS);		/* read it just to clear it */
+
+	/* zero out the chip Hash Filter registers */
+	for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); 	/* bits 15 - 0 */
+	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); 	/* bits 31 - 16 */
+	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); 	/* bits 47 - 32 */
+	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); 	/* bits 63 - 48 */
+
+	pWord16 = (unsigned short *)dev->dev_addr;
+	bmwrite(dev, MADD0, *pWord16++);
+	bmwrite(dev, MADD1, *pWord16++);
+	bmwrite(dev, MADD2, *pWord16);
+
+	bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
+
+	bmwrite(dev, INTDISABLE, EnableNormal);
+}
+
+#if 0
+static void
+bmac_disable_interrupts(struct net_device *dev)
+{
+	bmwrite(dev, INTDISABLE, DisableAll);
+}
+
+static void
+bmac_enable_interrupts(struct net_device *dev)
+{
+	bmwrite(dev, INTDISABLE, EnableNormal);
+}
+#endif
+
+
+static void
+bmac_start_chip(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	unsigned short	oldConfig;
+
+	/* enable rx dma channel */
+	dbdma_continue(rd);
+
+	oldConfig = bmread(dev, TXCFG);
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+	/* turn on rx plus any other bits already on (promiscuous possibly) */
+	oldConfig = bmread(dev, RXCFG);
+	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+	udelay(20000);
+}
+
+static void
+bmac_init_phy(struct net_device *dev)
+{
+	unsigned int addr;
+	struct bmac_data *bp = netdev_priv(dev);
+
+	printk(KERN_DEBUG "phy registers:");
+	for (addr = 0; addr < 32; ++addr) {
+		if ((addr & 7) == 0)
+			printk(KERN_DEBUG);
+		printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr));
+	}
+	printk(KERN_CONT "\n");
+
+	if (bp->is_bmac_plus) {
+		unsigned int capable, ctrl;
+
+		ctrl = bmac_mif_read(dev, 0);
+		capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1;
+		if (bmac_mif_read(dev, 4) != capable ||
+		    (ctrl & 0x1000) == 0) {
+			bmac_mif_write(dev, 4, capable);
+			bmac_mif_write(dev, 0, 0x1200);
+		} else
+			bmac_mif_write(dev, 0, 0x1000);
+	}
+}
+
+static void bmac_init_chip(struct net_device *dev)
+{
+	bmac_init_phy(dev);
+	bmac_init_registers(dev);
+}
+
+#ifdef CONFIG_PM
+static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
+{
+	struct net_device* dev = macio_get_drvdata(mdev);
+	struct bmac_data *bp = netdev_priv(dev);
+	unsigned long flags;
+	unsigned short config;
+	int i;
+
+	netif_device_detach(dev);
+	/* prolly should wait for dma to finish & turn off the chip */
+	spin_lock_irqsave(&bp->lock, flags);
+	if (bp->timeout_active) {
+		del_timer(&bp->tx_timeout);
+		bp->timeout_active = 0;
+	}
+	disable_irq(dev->irq);
+	disable_irq(bp->tx_dma_intr);
+	disable_irq(bp->rx_dma_intr);
+	bp->sleeping = 1;
+	spin_unlock_irqrestore(&bp->lock, flags);
+	if (bp->opened) {
+		volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+		volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+
+		config = bmread(dev, RXCFG);
+		bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+		config = bmread(dev, TXCFG);
+       		bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+		bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+       		/* disable rx and tx dma */
+		rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+		td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+       		/* free some skb's */
+       		for (i=0; i<N_RX_RING; i++) {
+       			if (bp->rx_bufs[i] != NULL) {
+       				dev_kfree_skb(bp->rx_bufs[i]);
+       				bp->rx_bufs[i] = NULL;
+       			}
+       		}
+       		for (i = 0; i<N_TX_RING; i++) {
+			if (bp->tx_bufs[i] != NULL) {
+		       		dev_kfree_skb(bp->tx_bufs[i]);
+	       			bp->tx_bufs[i] = NULL;
+		       	}
+		}
+	}
+       	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+	return 0;
+}
+
+static int bmac_resume(struct macio_dev *mdev)
+{
+	struct net_device* dev = macio_get_drvdata(mdev);
+	struct bmac_data *bp = netdev_priv(dev);
+
+	/* see if this is enough */
+	if (bp->opened)
+		bmac_reset_and_enable(dev);
+
+	enable_irq(dev->irq);
+       	enable_irq(bp->tx_dma_intr);
+       	enable_irq(bp->rx_dma_intr);
+       	netif_device_attach(dev);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static int bmac_set_address(struct net_device *dev, void *addr)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	unsigned char *p = addr;
+	unsigned short *pWord16;
+	unsigned long flags;
+	int i;
+
+	XXDEBUG(("bmac: enter set_address\n"));
+	spin_lock_irqsave(&bp->lock, flags);
+
+	for (i = 0; i < 6; ++i) {
+		dev->dev_addr[i] = p[i];
+	}
+	/* load up the hardware address */
+	pWord16  = (unsigned short *)dev->dev_addr;
+	bmwrite(dev, MADD0, *pWord16++);
+	bmwrite(dev, MADD1, *pWord16++);
+	bmwrite(dev, MADD2, *pWord16);
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+	XXDEBUG(("bmac: exit set_address\n"));
+	return 0;
+}
+
+static inline void bmac_set_timeout(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	if (bp->timeout_active)
+		del_timer(&bp->tx_timeout);
+	bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+	add_timer(&bp->tx_timeout);
+	bp->timeout_active = 1;
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static void
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
+{
+	void *vaddr;
+	unsigned long baddr;
+	unsigned long len;
+
+	len = skb->len;
+	vaddr = skb->data;
+	baddr = virt_to_bus(vaddr);
+
+	dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
+}
+
+static void
+bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
+{
+	unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf;
+
+	dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN,
+		     virt_to_bus(addr), 0);
+}
+
+static void
+bmac_init_tx_ring(struct bmac_data *bp)
+{
+	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+
+	memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
+
+	bp->tx_empty = 0;
+	bp->tx_fill = 0;
+	bp->tx_fullup = 0;
+
+	/* put a branch at the end of the tx command list */
+	dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
+		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
+
+	/* reset tx dma */
+	dbdma_reset(td);
+	out_le32(&td->wait_sel, 0x00200020);
+	out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
+}
+
+static int
+bmac_init_rx_ring(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	int i;
+	struct sk_buff *skb;
+
+	/* initialize list of sk_buffs for receiving and set up recv dma */
+	memset((char *)bp->rx_cmds, 0,
+	       (N_RX_RING + 1) * sizeof(struct dbdma_cmd));
+	for (i = 0; i < N_RX_RING; i++) {
+		if ((skb = bp->rx_bufs[i]) == NULL) {
+			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
+			if (skb != NULL)
+				skb_reserve(skb, 2);
+		}
+		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
+	}
+
+	bp->rx_empty = 0;
+	bp->rx_fill = i;
+
+	/* Put a branch back to the beginning of the receive command list */
+	dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
+		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
+
+	/* start rx dma */
+	dbdma_reset(rd);
+	out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
+
+	return 1;
+}
+
+
+static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+	int i;
+
+	/* see if there's a free slot in the tx ring */
+	/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
+	/* 	     bp->tx_empty, bp->tx_fill)); */
+	i = bp->tx_fill + 1;
+	if (i >= N_TX_RING)
+		i = 0;
+	if (i == bp->tx_empty) {
+		netif_stop_queue(dev);
+		bp->tx_fullup = 1;
+		XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
+		return -1;		/* can't take it at the moment */
+	}
+
+	dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
+
+	bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]);
+
+	bp->tx_bufs[bp->tx_fill] = skb;
+	bp->tx_fill = i;
+
+	dev->stats.tx_bytes += skb->len;
+
+	dbdma_continue(td);
+
+	return 0;
+}
+
+static int rxintcount;
+
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	volatile struct dbdma_cmd *cp;
+	int i, nb, stat;
+	struct sk_buff *skb;
+	unsigned int residual;
+	int last;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	if (++rxintcount < 10) {
+		XXDEBUG(("bmac_rxdma_intr\n"));
+	}
+
+	last = -1;
+	i = bp->rx_empty;
+
+	while (1) {
+		cp = &bp->rx_cmds[i];
+		stat = le16_to_cpu(cp->xfer_status);
+		residual = le16_to_cpu(cp->res_count);
+		if ((stat & ACTIVE) == 0)
+			break;
+		nb = RX_BUFLEN - residual - 2;
+		if (nb < (ETHERMINPACKET - ETHERCRC)) {
+			skb = NULL;
+			dev->stats.rx_length_errors++;
+			dev->stats.rx_errors++;
+		} else {
+			skb = bp->rx_bufs[i];
+			bp->rx_bufs[i] = NULL;
+		}
+		if (skb != NULL) {
+			nb -= ETHERCRC;
+			skb_put(skb, nb);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			++dev->stats.rx_packets;
+			dev->stats.rx_bytes += nb;
+		} else {
+			++dev->stats.rx_dropped;
+		}
+		if ((skb = bp->rx_bufs[i]) == NULL) {
+			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
+			if (skb != NULL)
+				skb_reserve(bp->rx_bufs[i], 2);
+		}
+		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
+		cp->res_count = cpu_to_le16(0);
+		cp->xfer_status = cpu_to_le16(0);
+		last = i;
+		if (++i >= N_RX_RING) i = 0;
+	}
+
+	if (last != -1) {
+		bp->rx_fill = last;
+		bp->rx_empty = i;
+	}
+
+	dbdma_continue(rd);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	if (rxintcount < 10) {
+		XXDEBUG(("bmac_rxdma_intr done\n"));
+	}
+	return IRQ_HANDLED;
+}
+
+static int txintcount;
+
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_cmd *cp;
+	int stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	if (txintcount++ < 10) {
+		XXDEBUG(("bmac_txdma_intr\n"));
+	}
+
+	/*     del_timer(&bp->tx_timeout); */
+	/*     bp->timeout_active = 0; */
+
+	while (1) {
+		cp = &bp->tx_cmds[bp->tx_empty];
+		stat = le16_to_cpu(cp->xfer_status);
+		if (txintcount < 10) {
+			XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
+		}
+		if (!(stat & ACTIVE)) {
+			/*
+			 * status field might not have been filled by DBDMA
+			 */
+			if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr)))
+				break;
+		}
+
+		if (bp->tx_bufs[bp->tx_empty]) {
+			++dev->stats.tx_packets;
+			dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
+		}
+		bp->tx_bufs[bp->tx_empty] = NULL;
+		bp->tx_fullup = 0;
+		netif_wake_queue(dev);
+		if (++bp->tx_empty >= N_TX_RING)
+			bp->tx_empty = 0;
+		if (bp->tx_empty == bp->tx_fill)
+			break;
+	}
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	if (txintcount < 10) {
+		XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
+	}
+
+	bmac_start(dev);
+	return IRQ_HANDLED;
+}
+
+#ifndef SUNHME_MULTICAST
+/* Real fast bit-reversal algorithm, 6-bit values */
+static int reverse6[64] = {
+	0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
+	0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
+	0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
+	0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
+	0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
+	0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
+	0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
+	0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
+};
+
+static unsigned int
+crc416(unsigned int curval, unsigned short nxtval)
+{
+	register unsigned int counter, cur = curval, next = nxtval;
+	register int high_crc_set, low_data_set;
+
+	/* Swap bytes */
+	next = ((next & 0x00FF) << 8) | (next >> 8);
+
+	/* Compute bit-by-bit */
+	for (counter = 0; counter < 16; ++counter) {
+		/* is high CRC bit set? */
+		if ((cur & 0x80000000) == 0) high_crc_set = 0;
+		else high_crc_set = 1;
+
+		cur = cur << 1;
+
+		if ((next & 0x0001) == 0) low_data_set = 0;
+		else low_data_set = 1;
+
+		next = next >> 1;
+
+		/* do the XOR */
+		if (high_crc_set ^ low_data_set) cur = cur ^ CRC32_POLY_BE;
+	}
+	return cur;
+}
+
+static unsigned int
+bmac_crc(unsigned short *address)
+{
+	unsigned int newcrc;
+
+	XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+	newcrc = crc416(0xffffffff, *address);	/* address bits 47 - 32 */
+	newcrc = crc416(newcrc, address[1]);	/* address bits 31 - 16 */
+	newcrc = crc416(newcrc, address[2]);	/* address bits 15 - 0  */
+
+	return(newcrc);
+}
+
+/*
+ * Add requested mcast addr to BMac's hash table filter.
+ *
+ */
+
+static void
+bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+{
+	unsigned int	 crc;
+	unsigned short	 mask;
+
+	if (!(*addr)) return;
+	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
+	if (bp->hash_use_count[crc]++) return; /* This bit is already set */
+	mask = crc % 16;
+	mask = (unsigned char)1 << mask;
+	bp->hash_use_count[crc/16] |= mask;
+}
+
+static void
+bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+{
+	unsigned int crc;
+	unsigned char mask;
+
+	/* Now, delete the address from the filter copy, as indicated */
+	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
+	if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
+	if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
+	mask = crc % 16;
+	mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
+	bp->hash_table_mask[crc/16] &= mask;
+}
+
+/*
+ * Sync the adapter with the software copy of the multicast mask
+ *  (logical address filter).
+ */
+
+static void
+bmac_rx_off(struct net_device *dev)
+{
+	unsigned short rx_cfg;
+
+	rx_cfg = bmread(dev, RXCFG);
+	rx_cfg &= ~RxMACEnable;
+	bmwrite(dev, RXCFG, rx_cfg);
+	do {
+		rx_cfg = bmread(dev, RXCFG);
+	}  while (rx_cfg & RxMACEnable);
+}
+
+unsigned short
+bmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable)
+{
+	unsigned short rx_cfg;
+
+	rx_cfg = bmread(dev, RXCFG);
+	rx_cfg |= RxMACEnable;
+	if (hash_enable) rx_cfg |= RxHashFilterEnable;
+	else rx_cfg &= ~RxHashFilterEnable;
+	if (promisc_enable) rx_cfg |= RxPromiscEnable;
+	else rx_cfg &= ~RxPromiscEnable;
+	bmwrite(dev, RXRST, RxResetValue);
+	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
+	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+	bmwrite(dev, RXCFG, rx_cfg );
+	return rx_cfg;
+}
+
+static void
+bmac_update_hash_table_mask(struct net_device *dev, struct bmac_data *bp)
+{
+	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+}
+
+#if 0
+static void
+bmac_add_multi(struct net_device *dev,
+	       struct bmac_data *bp, unsigned char *addr)
+{
+	/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
+	bmac_addhash(bp, addr);
+	bmac_rx_off(dev);
+	bmac_update_hash_table_mask(dev, bp);
+	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+	/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
+}
+
+static void
+bmac_remove_multi(struct net_device *dev,
+		  struct bmac_data *bp, unsigned char *addr)
+{
+	bmac_removehash(bp, addr);
+	bmac_rx_off(dev);
+	bmac_update_hash_table_mask(dev, bp);
+	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+}
+#endif
+
+/* Set or clear the multicast filter for this adaptor.
+    num_addrs == -1	Promiscuous mode, receive all packets
+    num_addrs == 0	Normal mode, clear multicast list
+    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void bmac_set_multicast(struct net_device *dev)
+{
+	struct netdev_hw_addr *ha;
+	struct bmac_data *bp = netdev_priv(dev);
+	int num_addrs = netdev_mc_count(dev);
+	unsigned short rx_cfg;
+	int i;
+
+	if (bp->sleeping)
+		return;
+
+	XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
+
+	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
+		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
+		bmac_update_hash_table_mask(dev, bp);
+		rx_cfg = bmac_rx_on(dev, 1, 0);
+		XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
+	} else if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
+		rx_cfg = bmread(dev, RXCFG);
+		rx_cfg |= RxPromiscEnable;
+		bmwrite(dev, RXCFG, rx_cfg);
+		rx_cfg = bmac_rx_on(dev, 0, 1);
+		XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
+	} else {
+		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+		for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
+		if (num_addrs == 0) {
+			rx_cfg = bmac_rx_on(dev, 0, 0);
+			XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
+		} else {
+			netdev_for_each_mc_addr(ha, dev)
+				bmac_addhash(bp, ha->addr);
+			bmac_update_hash_table_mask(dev, bp);
+			rx_cfg = bmac_rx_on(dev, 1, 0);
+			XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
+		}
+	}
+	/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
+}
+#else /* ifdef SUNHME_MULTICAST */
+
+/* The version of set_multicast below was lifted from sunhme.c */
+
+static void bmac_set_multicast(struct net_device *dev)
+{
+	struct netdev_hw_addr *ha;
+	unsigned short rx_cfg;
+	u32 crc;
+
+	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
+		bmwrite(dev, BHASH0, 0xffff);
+		bmwrite(dev, BHASH1, 0xffff);
+		bmwrite(dev, BHASH2, 0xffff);
+		bmwrite(dev, BHASH3, 0xffff);
+	} else if(dev->flags & IFF_PROMISC) {
+		rx_cfg = bmread(dev, RXCFG);
+		rx_cfg |= RxPromiscEnable;
+		bmwrite(dev, RXCFG, rx_cfg);
+	} else {
+		u16 hash_table[4] = { 0 };
+
+		rx_cfg = bmread(dev, RXCFG);
+		rx_cfg &= ~RxPromiscEnable;
+		bmwrite(dev, RXCFG, rx_cfg);
+
+		netdev_for_each_mc_addr(ha, dev) {
+			crc = ether_crc_le(6, ha->addr);
+			crc >>= 26;
+			hash_table[crc >> 4] |= 1 << (crc & 0xf);
+		}
+		bmwrite(dev, BHASH0, hash_table[0]);
+		bmwrite(dev, BHASH1, hash_table[1]);
+		bmwrite(dev, BHASH2, hash_table[2]);
+		bmwrite(dev, BHASH3, hash_table[3]);
+	}
+}
+#endif /* SUNHME_MULTICAST */
+
+static int miscintcount;
+
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	unsigned int status = bmread(dev, STATUS);
+	if (miscintcount++ < 10) {
+		XXDEBUG(("bmac_misc_intr\n"));
+	}
+	/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+	/*     bmac_txdma_intr_inner(irq, dev_id); */
+	/*   if (status & FrameReceived) dev->stats.rx_dropped++; */
+	if (status & RxErrorMask) dev->stats.rx_errors++;
+	if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
+	if (status & RxLenCntExp) dev->stats.rx_length_errors++;
+	if (status & RxOverFlow) dev->stats.rx_over_errors++;
+	if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
+
+	/*   if (status & FrameSent) dev->stats.tx_dropped++; */
+	if (status & TxErrorMask) dev->stats.tx_errors++;
+	if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
+	if (status & TxNormalCollExp) dev->stats.collisions++;
+	return IRQ_HANDLED;
+}
+
+/*
+ * Procedure for reading EEPROM
+ */
+#define SROMAddressLength	5
+#define DataInOn		0x0008
+#define DataInOff		0x0000
+#define Clk			0x0002
+#define ChipSelect		0x0001
+#define SDIShiftCount		3
+#define SD0ShiftCount		2
+#define	DelayValue		1000	/* number of microseconds */
+#define SROMStartOffset		10	/* this is in words */
+#define SROMReadCount		3	/* number of words to read from SROM */
+#define SROMAddressBits		6
+#define EnetAddressOffset	20
+
+static unsigned char
+bmac_clock_out_bit(struct net_device *dev)
+{
+	unsigned short         data;
+	unsigned short         val;
+
+	bmwrite(dev, SROMCSR, ChipSelect | Clk);
+	udelay(DelayValue);
+
+	data = bmread(dev, SROMCSR);
+	udelay(DelayValue);
+	val = (data >> SD0ShiftCount) & 1;
+
+	bmwrite(dev, SROMCSR, ChipSelect);
+	udelay(DelayValue);
+
+	return val;
+}
+
+static void
+bmac_clock_in_bit(struct net_device *dev, unsigned int val)
+{
+	unsigned short data;
+
+	if (val != 0 && val != 1) return;
+
+	data = (val << SDIShiftCount);
+	bmwrite(dev, SROMCSR, data | ChipSelect  );
+	udelay(DelayValue);
+
+	bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
+	udelay(DelayValue);
+
+	bmwrite(dev, SROMCSR, data | ChipSelect);
+	udelay(DelayValue);
+}
+
+static void
+reset_and_select_srom(struct net_device *dev)
+{
+	/* first reset */
+	bmwrite(dev, SROMCSR, 0);
+	udelay(DelayValue);
+
+	/* send it the read command (110) */
+	bmac_clock_in_bit(dev, 1);
+	bmac_clock_in_bit(dev, 1);
+	bmac_clock_in_bit(dev, 0);
+}
+
+static unsigned short
+read_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len)
+{
+	unsigned short data, val;
+	int i;
+
+	/* send out the address we want to read from */
+	for (i = 0; i < addr_len; i++)	{
+		val = addr >> (addr_len-i-1);
+		bmac_clock_in_bit(dev, val & 1);
+	}
+
+	/* Now read in the 16-bit data */
+	data = 0;
+	for (i = 0; i < 16; i++)	{
+		val = bmac_clock_out_bit(dev);
+		data <<= 1;
+		data |= val;
+	}
+	bmwrite(dev, SROMCSR, 0);
+
+	return data;
+}
+
+/*
+ * It looks like Cogent and SMC use different methods for calculating
+ * checksums. What a pain..
+ */
+
+static int
+bmac_verify_checksum(struct net_device *dev)
+{
+	unsigned short data, storedCS;
+
+	reset_and_select_srom(dev);
+	data = read_srom(dev, 3, SROMAddressBits);
+	storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
+
+	return 0;
+}
+
+
+static void
+bmac_get_station_address(struct net_device *dev, unsigned char *ea)
+{
+	int i;
+	unsigned short data;
+
+	for (i = 0; i < 6; i++)
+		{
+			reset_and_select_srom(dev);
+			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+			ea[2*i]   = bitrev8(data & 0x0ff);
+			ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
+		}
+}
+
+static void bmac_reset_and_enable(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	unsigned long flags;
+	struct sk_buff *skb;
+	unsigned char *data;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	bmac_enable_and_reset_chip(dev);
+	bmac_init_tx_ring(bp);
+	bmac_init_rx_ring(dev);
+	bmac_init_chip(dev);
+	bmac_start_chip(dev);
+	bmwrite(dev, INTDISABLE, EnableNormal);
+	bp->sleeping = 0;
+
+	/*
+	 * It seems that the bmac can't receive until it's transmitted
+	 * a packet.  So we give it a dummy packet to transmit.
+	 */
+	skb = netdev_alloc_skb(dev, ETHERMINPACKET);
+	if (skb != NULL) {
+		data = skb_put_zero(skb, ETHERMINPACKET);
+		memcpy(data, dev->dev_addr, ETH_ALEN);
+		memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN);
+		bmac_transmit_packet(skb, dev);
+	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static const struct ethtool_ops bmac_ethtool_ops = {
+	.get_link		= ethtool_op_get_link,
+};
+
+static const struct net_device_ops bmac_netdev_ops = {
+	.ndo_open		= bmac_open,
+	.ndo_stop		= bmac_close,
+	.ndo_start_xmit		= bmac_output,
+	.ndo_set_rx_mode	= bmac_set_multicast,
+	.ndo_set_mac_address	= bmac_set_address,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static int bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
+{
+	int j, rev, ret;
+	struct bmac_data *bp;
+	const unsigned char *prop_addr;
+	unsigned char addr[6];
+	struct net_device *dev;
+	int is_bmac_plus = ((int)match->data) != 0;
+
+	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
+		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
+		return -ENODEV;
+	}
+	prop_addr = of_get_property(macio_get_of_node(mdev),
+			"mac-address", NULL);
+	if (prop_addr == NULL) {
+		prop_addr = of_get_property(macio_get_of_node(mdev),
+				"local-mac-address", NULL);
+		if (prop_addr == NULL) {
+			printk(KERN_ERR "BMAC: Can't get mac-address\n");
+			return -ENODEV;
+		}
+	}
+	memcpy(addr, prop_addr, sizeof(addr));
+
+	dev = alloc_etherdev(PRIV_BYTES);
+	if (!dev)
+		return -ENOMEM;
+
+	bp = netdev_priv(dev);
+	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
+	macio_set_drvdata(mdev, dev);
+
+	bp->mdev = mdev;
+	spin_lock_init(&bp->lock);
+
+	if (macio_request_resources(mdev, "bmac")) {
+		printk(KERN_ERR "BMAC: can't request IO resource !\n");
+		goto out_free;
+	}
+
+	dev->base_addr = (unsigned long)
+		ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0));
+	if (dev->base_addr == 0)
+		goto out_release;
+
+	dev->irq = macio_irq(mdev, 0);
+
+	bmac_enable_and_reset_chip(dev);
+	bmwrite(dev, INTDISABLE, DisableAll);
+
+	rev = addr[0] == 0 && addr[1] == 0xA0;
+	for (j = 0; j < 6; ++j)
+		dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
+
+	/* Enable chip without interrupts for now */
+	bmac_enable_and_reset_chip(dev);
+	bmwrite(dev, INTDISABLE, DisableAll);
+
+	dev->netdev_ops = &bmac_netdev_ops;
+	dev->ethtool_ops = &bmac_ethtool_ops;
+
+	bmac_get_station_address(dev, addr);
+	if (bmac_verify_checksum(dev) != 0)
+		goto err_out_iounmap;
+
+	bp->is_bmac_plus = is_bmac_plus;
+	bp->tx_dma = ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1));
+	if (!bp->tx_dma)
+		goto err_out_iounmap;
+	bp->tx_dma_intr = macio_irq(mdev, 1);
+	bp->rx_dma = ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2));
+	if (!bp->rx_dma)
+		goto err_out_iounmap_tx;
+	bp->rx_dma_intr = macio_irq(mdev, 2);
+
+	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
+	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
+
+	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
+	skb_queue_head_init(bp->queue);
+
+	timer_setup(&bp->tx_timeout, bmac_tx_timeout, 0);
+
+	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
+	if (ret) {
+		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
+		goto err_out_iounmap_rx;
+	}
+	ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev);
+	if (ret) {
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr);
+		goto err_out_irq0;
+	}
+	ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
+	if (ret) {
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr);
+		goto err_out_irq1;
+	}
+
+	/* Mask chip interrupts and disable chip, will be
+	 * re-enabled on open()
+	 */
+	disable_irq(dev->irq);
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+
+	if (register_netdev(dev) != 0) {
+		printk(KERN_ERR "BMAC: Ethernet registration failed\n");
+		goto err_out_irq2;
+	}
+
+	printk(KERN_INFO "%s: BMAC%s at %pM",
+	       dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr);
+	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+	printk("\n");
+
+	return 0;
+
+err_out_irq2:
+	free_irq(bp->rx_dma_intr, dev);
+err_out_irq1:
+	free_irq(bp->tx_dma_intr, dev);
+err_out_irq0:
+	free_irq(dev->irq, dev);
+err_out_iounmap_rx:
+	iounmap(bp->rx_dma);
+err_out_iounmap_tx:
+	iounmap(bp->tx_dma);
+err_out_iounmap:
+	iounmap((void __iomem *)dev->base_addr);
+out_release:
+	macio_release_resources(mdev);
+out_free:
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+	free_netdev(dev);
+
+	return -ENODEV;
+}
+
+static int bmac_open(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	/* XXDEBUG(("bmac: enter open\n")); */
+	/* reset the chip */
+	bp->opened = 1;
+	bmac_reset_and_enable(dev);
+	enable_irq(dev->irq);
+	return 0;
+}
+
+static int bmac_close(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+	unsigned short config;
+	int i;
+
+	bp->sleeping = 1;
+
+	/* disable rx and tx */
+	config = bmread(dev, RXCFG);
+	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+
+	config = bmread(dev, TXCFG);
+	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+
+	bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+
+	/* disable rx and tx dma */
+	rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+	td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+
+	/* free some skb's */
+	XXDEBUG(("bmac: free rx bufs\n"));
+	for (i=0; i<N_RX_RING; i++) {
+		if (bp->rx_bufs[i] != NULL) {
+			dev_kfree_skb(bp->rx_bufs[i]);
+			bp->rx_bufs[i] = NULL;
+		}
+	}
+	XXDEBUG(("bmac: free tx bufs\n"));
+	for (i = 0; i<N_TX_RING; i++) {
+		if (bp->tx_bufs[i] != NULL) {
+			dev_kfree_skb(bp->tx_bufs[i]);
+			bp->tx_bufs[i] = NULL;
+		}
+	}
+	XXDEBUG(("bmac: all bufs freed\n"));
+
+	bp->opened = 0;
+	disable_irq(dev->irq);
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+
+	return 0;
+}
+
+static void
+bmac_start(struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	int i;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	if (bp->sleeping)
+		return;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	while (1) {
+		i = bp->tx_fill + 1;
+		if (i >= N_TX_RING)
+			i = 0;
+		if (i == bp->tx_empty)
+			break;
+		skb = skb_dequeue(bp->queue);
+		if (skb == NULL)
+			break;
+		bmac_transmit_packet(skb, dev);
+	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static netdev_tx_t
+bmac_output(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	skb_queue_tail(bp->queue, skb);
+	bmac_start(dev);
+	return NETDEV_TX_OK;
+}
+
+static void bmac_tx_timeout(struct timer_list *t)
+{
+	struct bmac_data *bp = from_timer(bp, t, tx_timeout);
+	struct net_device *dev = macio_get_drvdata(bp->mdev);
+	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
+	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
+	volatile struct dbdma_cmd *cp;
+	unsigned long flags;
+	unsigned short config, oldConfig;
+	int i;
+
+	XXDEBUG(("bmac: tx_timeout called\n"));
+	spin_lock_irqsave(&bp->lock, flags);
+	bp->timeout_active = 0;
+
+	/* update various counters */
+/*     	bmac_handle_misc_intrs(bp, 0); */
+
+	cp = &bp->tx_cmds[bp->tx_empty];
+/*	XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
+/* 	   le32_to_cpu(td->status), le16_to_cpu(cp->xfer_status), bp->tx_bad_runt, */
+/* 	   mb->pr, mb->xmtfs, mb->fifofc)); */
+
+	/* turn off both tx and rx and reset the chip */
+	config = bmread(dev, RXCFG);
+	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+	config = bmread(dev, TXCFG);
+	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+	out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+	printk(KERN_ERR "bmac: transmit timeout - resetting\n");
+	bmac_enable_and_reset_chip(dev);
+
+	/* restart rx dma */
+	cp = bus_to_virt(le32_to_cpu(rd->cmdptr));
+	out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+	out_le16(&cp->xfer_status, 0);
+	out_le32(&rd->cmdptr, virt_to_bus(cp));
+	out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
+
+	/* fix up the transmit side */
+	XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
+		 bp->tx_empty, bp->tx_fill, bp->tx_fullup));
+	i = bp->tx_empty;
+	++dev->stats.tx_errors;
+	if (i != bp->tx_fill) {
+		dev_kfree_skb(bp->tx_bufs[i]);
+		bp->tx_bufs[i] = NULL;
+		if (++i >= N_TX_RING) i = 0;
+		bp->tx_empty = i;
+	}
+	bp->tx_fullup = 0;
+	netif_wake_queue(dev);
+	if (i != bp->tx_fill) {
+		cp = &bp->tx_cmds[i];
+		out_le16(&cp->xfer_status, 0);
+		out_le16(&cp->command, OUTPUT_LAST);
+		out_le32(&td->cmdptr, virt_to_bus(cp));
+		out_le32(&td->control, DBDMA_SET(RUN));
+		/* 	bmac_set_timeout(dev); */
+		XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
+	}
+
+	/* turn it back on */
+	oldConfig = bmread(dev, RXCFG);
+	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+	oldConfig = bmread(dev, TXCFG);
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+#if 0
+static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+{
+	int i,*ip;
+
+	for (i=0;i< count;i++) {
+		ip = (int*)(cp+i);
+
+		printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+		       le32_to_cpup(ip+0),
+		       le32_to_cpup(ip+1),
+		       le32_to_cpup(ip+2),
+		       le32_to_cpup(ip+3));
+	}
+
+}
+#endif
+
+#if 0
+static int
+bmac_proc_info(char *buffer, char **start, off_t offset, int length)
+{
+	int len = 0;
+	off_t pos   = 0;
+	off_t begin = 0;
+	int i;
+
+	if (bmac_devs == NULL)
+		return -ENOSYS;
+
+	len += sprintf(buffer, "BMAC counters & registers\n");
+
+	for (i = 0; i<N_REG_ENTRIES; i++) {
+		len += sprintf(buffer + len, "%s: %#08x\n",
+			       reg_entries[i].name,
+			       bmread(bmac_devs, reg_entries[i].reg_offset));
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+
+		if (pos > offset+length) break;
+	}
+
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+
+	if (len > length) len = length;
+
+	return len;
+}
+#endif
+
+static int bmac_remove(struct macio_dev *mdev)
+{
+	struct net_device *dev = macio_get_drvdata(mdev);
+	struct bmac_data *bp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+
+       	free_irq(dev->irq, dev);
+	free_irq(bp->tx_dma_intr, dev);
+	free_irq(bp->rx_dma_intr, dev);
+
+	iounmap((void __iomem *)dev->base_addr);
+	iounmap(bp->tx_dma);
+	iounmap(bp->rx_dma);
+
+	macio_release_resources(mdev);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+static const struct of_device_id bmac_match[] =
+{
+	{
+	.name 		= "bmac",
+	.data		= (void *)0,
+	},
+	{
+	.type		= "network",
+	.compatible	= "bmac+",
+	.data		= (void *)1,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE (of, bmac_match);
+
+static struct macio_driver bmac_driver =
+{
+	.driver = {
+		.name 		= "bmac",
+		.owner		= THIS_MODULE,
+		.of_match_table	= bmac_match,
+	},
+	.probe		= bmac_probe,
+	.remove		= bmac_remove,
+#ifdef CONFIG_PM
+	.suspend	= bmac_suspend,
+	.resume		= bmac_resume,
+#endif
+};
+
+
+static int __init bmac_init(void)
+{
+	if (bmac_emergency_rxbuf == NULL) {
+		bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
+		if (bmac_emergency_rxbuf == NULL)
+			return -ENOMEM;
+	}
+
+	return macio_register_driver(&bmac_driver);
+}
+
+static void __exit bmac_exit(void)
+{
+	macio_unregister_driver(&bmac_driver);
+
+	kfree(bmac_emergency_rxbuf);
+	bmac_emergency_rxbuf = NULL;
+}
+
+MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
+MODULE_LICENSE("GPL");
+
+module_init(bmac_init);
+module_exit(bmac_exit);
diff --git a/drivers/net/ethernet/apple/bmac.h b/drivers/net/ethernet/apple/bmac.h
new file mode 100644
index 0000000..a1d19d8
--- /dev/null
+++ b/drivers/net/ethernet/apple/bmac.h
@@ -0,0 +1,164 @@
+/*
+ * mace.h - definitions for the registers in the "Big Mac"
+ *  Ethernet controller found in PowerMac G3 models.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal"
+ * (HME) controller.  See sunhme.h
+ */
+
+
+/* register offsets */
+
+/* global status and control */
+#define	XIFC		0x000   /* low-level interface control */
+#	define	TxOutputEnable	0x0001 /* output driver enable */
+#	define	XIFLoopback	0x0002 /* Loopback-mode XIF enable */
+#	define	MIILoopback	0x0004 /* Loopback-mode MII enable */
+#	define	MIILoopbackBits	0x0006
+#	define	MIIBuffDisable	0x0008 /* MII receive buffer disable */
+#	define	SQETestEnable	0x0010 /* SQE test enable */
+#	define	SQETimeWindow	0x03e0 /* SQE time window */
+#	define	XIFLanceMode	0x0010 /* Lance mode enable */
+#	define	XIFLanceIPG0	0x03e0 /* Lance mode IPG0 */
+#define	TXFIFOCSR	0x100   /* transmit FIFO control */
+#	define	TxFIFOEnable	0x0001
+#define	TXTH		0x110   /* transmit threshold */
+#	define	TxThreshold	0x0004
+#define RXFIFOCSR	0x120   /* receive FIFO control */
+#	define	RxFIFOEnable	0x0001
+#define MEMADD		0x130   /* memory address, unknown function */
+#define MEMDATAHI	0x140   /* memory data high, presently unused in driver */
+#define MEMDATALO	0x150   /* memory data low, presently unused in driver */
+#define XCVRIF		0x160   /* transceiver interface control */
+#	define	COLActiveLow	0x0002
+#	define	SerialMode	0x0004
+#	define	ClkBit		0x0008
+#	define	LinkStatus	0x0100
+#define CHIPID          0x170   /* chip ID */
+#define	MIFCSR		0x180   /* ??? */
+#define	SROMCSR		0x190   /* SROM control */
+#	define	ChipSelect	0x0001
+#	define	Clk		0x0002
+#define TXPNTR		0x1a0   /* transmit pointer */
+#define	RXPNTR		0x1b0   /* receive pointer */
+#define	STATUS		0x200   /* status--reading this clears it */
+#define	INTDISABLE	0x210   /* interrupt enable/disable control */
+/* bits below are the same in both STATUS and INTDISABLE registers */
+#	define	FrameReceived	0x00000001 /* Received a frame */
+#	define	RxFrameCntExp	0x00000002 /* Receive frame counter expired */
+#	define	RxAlignCntExp	0x00000004 /* Align-error counter expired */
+#	define	RxCRCCntExp	0x00000008 /* CRC-error counter expired */
+#	define	RxLenCntExp	0x00000010 /* Length-error counter expired */
+#	define	RxOverFlow	0x00000020 /* Receive FIFO overflow */
+#	define	RxCodeViolation	0x00000040 /* Code-violation counter expired */
+#	define	SQETestError	0x00000080 /* Test error in XIF for SQE */
+#	define	FrameSent	0x00000100 /* Transmitted a frame */
+#	define	TxUnderrun	0x00000200 /* Transmit FIFO underrun */
+#	define	TxMaxSizeError	0x00000400 /* Max-packet size error */
+#	define	TxNormalCollExp	0x00000800 /* Normal-collision counter expired */
+#	define	TxExcessCollExp	0x00001000 /* Excess-collision counter expired */
+#	define	TxLateCollExp	0x00002000 /* Late-collision counter expired */
+#	define	TxNetworkCollExp 0x00004000 /* First-collision counter expired */
+#	define	TxDeferTimerExp	0x00008000 /* Defer-timer expired */
+#	define	RxFIFOToHost	0x00010000 /* Data moved from FIFO to host */
+#	define	RxNoDescriptors	0x00020000 /* No more receive descriptors */
+#	define	RxDMAError	0x00040000 /* Error during receive DMA */
+#	define	RxDMALateErr	0x00080000 /* Receive DMA, data late */
+#	define	RxParityErr	0x00100000 /* Parity error during receive DMA */
+#	define	RxTagError	0x00200000 /* Tag error during receive DMA */
+#	define	TxEOPError	0x00400000 /* Tx descriptor did not have EOP set */
+#	define	MIFIntrEvent	0x00800000 /* MIF is signaling an interrupt */
+#	define	TxHostToFIFO	0x01000000 /* Data moved from host to FIFO  */
+#	define	TxFIFOAllSent	0x02000000 /* Transmitted all packets in FIFO */
+#	define	TxDMAError	0x04000000 /* Error during transmit DMA */
+#	define	TxDMALateError	0x08000000 /* Late error during transmit DMA */
+#	define	TxParityError	0x10000000 /* Parity error during transmit DMA */
+#	define	TxTagError	0x20000000 /* Tag error during transmit DMA */
+#	define	PIOError	0x40000000 /* PIO access got an error */
+#	define	PIOParityError	0x80000000 /* PIO access got a parity error  */
+#	define	DisableAll	0xffffffff
+#	define	EnableAll	0x00000000
+/* #	define	NormalIntEvents	~(FrameReceived | FrameSent | TxUnderrun) */
+#	define	EnableNormal	~(FrameReceived | FrameSent)
+#	define	EnableErrors	(FrameReceived | FrameSent)
+#	define	RxErrorMask	(RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \
+				 RxLenCntExp | RxOverFlow | RxCodeViolation)
+#	define	TxErrorMask	(TxUnderrun | TxMaxSizeError | TxExcessCollExp | \
+				 TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp)
+
+/* transmit control */
+#define	TXRST		0x420   /* transmit reset */
+#	define	TxResetBit	0x0001
+#define	TXCFG		0x430   /* transmit configuration control*/
+#	define	TxMACEnable	0x0001 /* output driver enable */
+#	define	TxSlowMode	0x0020 /* enable slow mode */
+#	define	TxIgnoreColl	0x0040 /* ignore transmit collisions */
+#	define	TxNoFCS		0x0080 /* do not emit FCS */
+#	define	TxNoBackoff	0x0100 /* no backoff in case of collisions */
+#	define	TxFullDuplex	0x0200 /* enable full-duplex */
+#	define	TxNeverGiveUp	0x0400 /* don't give up on transmits */
+#define IPG1		0x440   /* Inter-packet gap 1 */
+#define IPG2		0x450   /* Inter-packet gap 2 */
+#define ALIMIT		0x460   /* Transmit attempt limit */
+#define SLOT		0x470   /* Transmit slot time */
+#define PALEN		0x480   /* Size of transmit preamble */
+#define PAPAT		0x490   /* Pattern for transmit preamble */
+#define TXSFD		0x4a0   /* Transmit frame delimiter */
+#define JAM		0x4b0   /* Jam size */
+#define TXMAX		0x4c0   /* Transmit max pkt size */
+#define TXMIN		0x4d0   /* Transmit min pkt size */
+#define PAREG		0x4e0   /* Count of transmit peak attempts */
+#define DCNT		0x4f0   /* Transmit defer timer */
+#define NCCNT		0x500   /* Transmit normal-collision counter */
+#define NTCNT		0x510   /* Transmit first-collision counter */
+#define EXCNT		0x520   /* Transmit excess-collision counter */
+#define LTCNT		0x530   /* Transmit late-collision counter */
+#define RSEED		0x540   /* Transmit random number seed */
+#define TXSM		0x550   /* Transmit state machine */
+
+/* receive control */
+#define RXRST		0x620   /* receive reset */
+#	define	RxResetValue	0x0000
+#define RXCFG		0x630   /* receive configuration control */
+#	define	RxMACEnable	0x0001 /* receiver overall enable */
+#	define	RxCFGReserved	0x0004
+#	define	RxPadStripEnab	0x0020 /* enable pad byte stripping */
+#	define	RxPromiscEnable	0x0040 /* turn on promiscuous mode */
+#	define	RxNoErrCheck	0x0080 /* disable receive error checking */
+#	define	RxCRCNoStrip	0x0100 /* disable auto-CRC-stripping */
+#	define	RxRejectOwnPackets 0x0200 /* don't receive our own packets */
+#	define	RxGrpPromisck	0x0400 /* enable group promiscuous mode */
+#	define	RxHashFilterEnable 0x0800 /* enable hash filter */
+#	define	RxAddrFilterEnable 0x1000 /* enable address filter */
+#define RXMAX		0x640   /* Max receive packet size */
+#define RXMIN		0x650   /* Min receive packet size */
+#define MADD2		0x660   /* our enet address, high part */
+#define MADD1		0x670   /* our enet address, middle part */
+#define MADD0		0x680   /* our enet address, low part */
+#define FRCNT		0x690   /* receive frame counter */
+#define LECNT		0x6a0   /* Receive excess length error counter */
+#define AECNT		0x6b0   /* Receive misaligned error counter */
+#define FECNT		0x6c0   /* Receive CRC error counter */
+#define RXSM		0x6d0   /* Receive state machine */
+#define RXCV		0x6e0   /* Receive code violation */
+
+#define BHASH3		0x700   /* multicast hash register */
+#define BHASH2		0x710   /* multicast hash register */
+#define BHASH1		0x720   /* multicast hash register */
+#define BHASH0		0x730   /* multicast hash register */
+
+#define AFR2		0x740   /* address filtering setup? */
+#define AFR1		0x750   /* address filtering setup? */
+#define AFR0		0x760   /* address filtering setup? */
+#define AFCR		0x770   /* address filter compare register? */
+#	define	EnableAllCompares 0x0fff
+
+/* bits in XIFC */
diff --git a/drivers/net/ethernet/apple/mace.c b/drivers/net/ethernet/apple/mace.c
new file mode 100644
index 0000000..68b9ee4
--- /dev/null
+++ b/drivers/net/ethernet/apple/mace.c
@@ -0,0 +1,1025 @@
+/*
+ * Network device driver for the MACE ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/crc32.h>
+#include <linux/spinlock.h>
+#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/macio.h>
+
+#include "mace.h"
+
+static int port_aaui = -1;
+
+#define N_RX_RING	8
+#define N_TX_RING	6
+#define MAX_TX_ACTIVE	1
+#define NCMDS_TX	1	/* dma commands per element in tx ring */
+#define RX_BUFLEN	(ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT	HZ	/* 1 second */
+
+/* Chip rev needs workaround on HW & multicast addr change */
+#define BROKEN_ADDRCHG_REV	0x0941
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR	0x80
+
+struct mace_data {
+    volatile struct mace __iomem *mace;
+    volatile struct dbdma_regs __iomem *tx_dma;
+    int tx_dma_intr;
+    volatile struct dbdma_regs __iomem *rx_dma;
+    int rx_dma_intr;
+    volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
+    volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
+    struct sk_buff *rx_bufs[N_RX_RING];
+    int rx_fill;
+    int rx_empty;
+    struct sk_buff *tx_bufs[N_TX_RING];
+    int tx_fill;
+    int tx_empty;
+    unsigned char maccc;
+    unsigned char tx_fullup;
+    unsigned char tx_active;
+    unsigned char tx_bad_runt;
+    struct timer_list tx_timeout;
+    int timeout_active;
+    int port_aaui;
+    int chipid;
+    struct macio_dev *mdev;
+    spinlock_t lock;
+};
+
+/*
+ * Number of bytes of private data per MACE: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES	(sizeof(struct mace_data) \
+	+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
+
+static int mace_open(struct net_device *dev);
+static int mace_close(struct net_device *dev);
+static netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static void mace_set_multicast(struct net_device *dev);
+static void mace_reset(struct net_device *dev);
+static int mace_set_address(struct net_device *dev, void *addr);
+static irqreturn_t mace_interrupt(int irq, void *dev_id);
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id);
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id);
+static void mace_set_timeout(struct net_device *dev);
+static void mace_tx_timeout(struct timer_list *t);
+static inline void dbdma_reset(volatile struct dbdma_regs __iomem *dma);
+static inline void mace_clean_rings(struct mace_data *mp);
+static void __mace_set_address(struct net_device *dev, void *addr);
+
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char *dummy_buf;
+
+static const struct net_device_ops mace_netdev_ops = {
+	.ndo_open		= mace_open,
+	.ndo_stop		= mace_close,
+	.ndo_start_xmit		= mace_xmit_start,
+	.ndo_set_rx_mode	= mace_set_multicast,
+	.ndo_set_mac_address	= mace_set_address,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static int mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
+{
+	struct device_node *mace = macio_get_of_node(mdev);
+	struct net_device *dev;
+	struct mace_data *mp;
+	const unsigned char *addr;
+	int j, rev, rc = -EBUSY;
+
+	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
+		printk(KERN_ERR "can't use MACE %pOF: need 3 addrs and 3 irqs\n",
+		       mace);
+		return -ENODEV;
+	}
+
+	addr = of_get_property(mace, "mac-address", NULL);
+	if (addr == NULL) {
+		addr = of_get_property(mace, "local-mac-address", NULL);
+		if (addr == NULL) {
+			printk(KERN_ERR "Can't get mac-address for MACE %pOF\n",
+			       mace);
+			return -ENODEV;
+		}
+	}
+
+	/*
+	 * lazy allocate the driver-wide dummy buffer. (Note that we
+	 * never have more than one MACE in the system anyway)
+	 */
+	if (dummy_buf == NULL) {
+		dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL);
+		if (dummy_buf == NULL)
+			return -ENOMEM;
+	}
+
+	if (macio_request_resources(mdev, "mace")) {
+		printk(KERN_ERR "MACE: can't request IO resources !\n");
+		return -EBUSY;
+	}
+
+	dev = alloc_etherdev(PRIV_BYTES);
+	if (!dev) {
+		rc = -ENOMEM;
+		goto err_release;
+	}
+	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
+
+	mp = netdev_priv(dev);
+	mp->mdev = mdev;
+	macio_set_drvdata(mdev, dev);
+
+	dev->base_addr = macio_resource_start(mdev, 0);
+	mp->mace = ioremap(dev->base_addr, 0x1000);
+	if (mp->mace == NULL) {
+		printk(KERN_ERR "MACE: can't map IO resources !\n");
+		rc = -ENOMEM;
+		goto err_free;
+	}
+	dev->irq = macio_irq(mdev, 0);
+
+	rev = addr[0] == 0 && addr[1] == 0xA0;
+	for (j = 0; j < 6; ++j) {
+		dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
+	}
+	mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
+			in_8(&mp->mace->chipid_lo);
+
+
+	mp = netdev_priv(dev);
+	mp->maccc = ENXMT | ENRCV;
+
+	mp->tx_dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
+	if (mp->tx_dma == NULL) {
+		printk(KERN_ERR "MACE: can't map TX DMA resources !\n");
+		rc = -ENOMEM;
+		goto err_unmap_io;
+	}
+	mp->tx_dma_intr = macio_irq(mdev, 1);
+
+	mp->rx_dma = ioremap(macio_resource_start(mdev, 2), 0x1000);
+	if (mp->rx_dma == NULL) {
+		printk(KERN_ERR "MACE: can't map RX DMA resources !\n");
+		rc = -ENOMEM;
+		goto err_unmap_tx_dma;
+	}
+	mp->rx_dma_intr = macio_irq(mdev, 2);
+
+	mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
+	mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
+
+	memset((char *) mp->tx_cmds, 0,
+	       (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+	timer_setup(&mp->tx_timeout, mace_tx_timeout, 0);
+	spin_lock_init(&mp->lock);
+	mp->timeout_active = 0;
+
+	if (port_aaui >= 0)
+		mp->port_aaui = port_aaui;
+	else {
+		/* Apple Network Server uses the AAUI port */
+		if (of_machine_is_compatible("AAPL,ShinerESB"))
+			mp->port_aaui = 1;
+		else {
+#ifdef CONFIG_MACE_AAUI_PORT
+			mp->port_aaui = 1;
+#else
+			mp->port_aaui = 0;
+#endif
+		}
+	}
+
+	dev->netdev_ops = &mace_netdev_ops;
+
+	/*
+	 * Most of what is below could be moved to mace_open()
+	 */
+	mace_reset(dev);
+
+	rc = request_irq(dev->irq, mace_interrupt, 0, "MACE", dev);
+	if (rc) {
+		printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+		goto err_unmap_rx_dma;
+	}
+	rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
+	if (rc) {
+		printk(KERN_ERR "MACE: can't get irq %d\n", mp->tx_dma_intr);
+		goto err_free_irq;
+	}
+	rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
+	if (rc) {
+		printk(KERN_ERR "MACE: can't get irq %d\n", mp->rx_dma_intr);
+		goto err_free_tx_irq;
+	}
+
+	rc = register_netdev(dev);
+	if (rc) {
+		printk(KERN_ERR "MACE: Cannot register net device, aborting.\n");
+		goto err_free_rx_irq;
+	}
+
+	printk(KERN_INFO "%s: MACE at %pM, chip revision %d.%d\n",
+	       dev->name, dev->dev_addr,
+	       mp->chipid >> 8, mp->chipid & 0xff);
+
+	return 0;
+
+ err_free_rx_irq:
+	free_irq(macio_irq(mdev, 2), dev);
+ err_free_tx_irq:
+	free_irq(macio_irq(mdev, 1), dev);
+ err_free_irq:
+	free_irq(macio_irq(mdev, 0), dev);
+ err_unmap_rx_dma:
+	iounmap(mp->rx_dma);
+ err_unmap_tx_dma:
+	iounmap(mp->tx_dma);
+ err_unmap_io:
+	iounmap(mp->mace);
+ err_free:
+	free_netdev(dev);
+ err_release:
+	macio_release_resources(mdev);
+
+	return rc;
+}
+
+static int mace_remove(struct macio_dev *mdev)
+{
+	struct net_device *dev = macio_get_drvdata(mdev);
+	struct mace_data *mp;
+
+	BUG_ON(dev == NULL);
+
+	macio_set_drvdata(mdev, NULL);
+
+	mp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+
+	free_irq(dev->irq, dev);
+	free_irq(mp->tx_dma_intr, dev);
+	free_irq(mp->rx_dma_intr, dev);
+
+	iounmap(mp->rx_dma);
+	iounmap(mp->tx_dma);
+	iounmap(mp->mace);
+
+	free_netdev(dev);
+
+	macio_release_resources(mdev);
+
+	return 0;
+}
+
+static void dbdma_reset(volatile struct dbdma_regs __iomem *dma)
+{
+    int i;
+
+    out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+    /*
+     * Yes this looks peculiar, but apparently it needs to be this
+     * way on some machines.
+     */
+    for (i = 200; i > 0; --i)
+	if (le32_to_cpu(dma->control) & RUN)
+	    udelay(1);
+}
+
+static void mace_reset(struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    int i;
+
+    /* soft-reset the chip */
+    i = 200;
+    while (--i) {
+	out_8(&mb->biucc, SWRST);
+	if (in_8(&mb->biucc) & SWRST) {
+	    udelay(10);
+	    continue;
+	}
+	break;
+    }
+    if (!i) {
+	printk(KERN_ERR "mace: cannot reset chip!\n");
+	return;
+    }
+
+    out_8(&mb->imr, 0xff);	/* disable all intrs for now */
+    i = in_8(&mb->ir);
+    out_8(&mb->maccc, 0);	/* turn off tx, rx */
+
+    out_8(&mb->biucc, XMTSP_64);
+    out_8(&mb->utr, RTRD);
+    out_8(&mb->fifocc, RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST);
+    out_8(&mb->xmtfc, AUTO_PAD_XMIT); /* auto-pad short frames */
+    out_8(&mb->rcvfc, 0);
+
+    /* load up the hardware address */
+    __mace_set_address(dev, dev->dev_addr);
+
+    /* clear the multicast filter */
+    if (mp->chipid == BROKEN_ADDRCHG_REV)
+	out_8(&mb->iac, LOGADDR);
+    else {
+	out_8(&mb->iac, ADDRCHG | LOGADDR);
+	while ((in_8(&mb->iac) & ADDRCHG) != 0)
+		;
+    }
+    for (i = 0; i < 8; ++i)
+	out_8(&mb->ladrf, 0);
+
+    /* done changing address */
+    if (mp->chipid != BROKEN_ADDRCHG_REV)
+	out_8(&mb->iac, 0);
+
+    if (mp->port_aaui)
+    	out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
+    else
+    	out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
+}
+
+static void __mace_set_address(struct net_device *dev, void *addr)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    unsigned char *p = addr;
+    int i;
+
+    /* load up the hardware address */
+    if (mp->chipid == BROKEN_ADDRCHG_REV)
+    	out_8(&mb->iac, PHYADDR);
+    else {
+    	out_8(&mb->iac, ADDRCHG | PHYADDR);
+	while ((in_8(&mb->iac) & ADDRCHG) != 0)
+	    ;
+    }
+    for (i = 0; i < 6; ++i)
+	out_8(&mb->padr, dev->dev_addr[i] = p[i]);
+    if (mp->chipid != BROKEN_ADDRCHG_REV)
+        out_8(&mb->iac, 0);
+}
+
+static int mace_set_address(struct net_device *dev, void *addr)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    unsigned long flags;
+
+    spin_lock_irqsave(&mp->lock, flags);
+
+    __mace_set_address(dev, addr);
+
+    /* note: setting ADDRCHG clears ENRCV */
+    out_8(&mb->maccc, mp->maccc);
+
+    spin_unlock_irqrestore(&mp->lock, flags);
+    return 0;
+}
+
+static inline void mace_clean_rings(struct mace_data *mp)
+{
+    int i;
+
+    /* free some skb's */
+    for (i = 0; i < N_RX_RING; ++i) {
+	if (mp->rx_bufs[i] != NULL) {
+	    dev_kfree_skb(mp->rx_bufs[i]);
+	    mp->rx_bufs[i] = NULL;
+	}
+    }
+    for (i = mp->tx_empty; i != mp->tx_fill; ) {
+	dev_kfree_skb(mp->tx_bufs[i]);
+	if (++i >= N_TX_RING)
+	    i = 0;
+    }
+}
+
+static int mace_open(struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
+    volatile struct dbdma_regs __iomem *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int i;
+    struct sk_buff *skb;
+    unsigned char *data;
+
+    /* reset the chip */
+    mace_reset(dev);
+
+    /* initialize list of sk_buffs for receiving and set up recv dma */
+    mace_clean_rings(mp);
+    memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
+    cp = mp->rx_cmds;
+    for (i = 0; i < N_RX_RING - 1; ++i) {
+	skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
+	if (!skb) {
+	    data = dummy_buf;
+	} else {
+	    skb_reserve(skb, 2);	/* so IP header lands on 4-byte bdry */
+	    data = skb->data;
+	}
+	mp->rx_bufs[i] = skb;
+	cp->req_count = cpu_to_le16(RX_BUFLEN);
+	cp->command = cpu_to_le16(INPUT_LAST + INTR_ALWAYS);
+	cp->phy_addr = cpu_to_le32(virt_to_bus(data));
+	cp->xfer_status = 0;
+	++cp;
+    }
+    mp->rx_bufs[i] = NULL;
+    cp->command = cpu_to_le16(DBDMA_STOP);
+    mp->rx_fill = i;
+    mp->rx_empty = 0;
+
+    /* Put a branch back to the beginning of the receive command list */
+    ++cp;
+    cp->command = cpu_to_le16(DBDMA_NOP + BR_ALWAYS);
+    cp->cmd_dep = cpu_to_le32(virt_to_bus(mp->rx_cmds));
+
+    /* start rx dma */
+    out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+    out_le32(&rd->cmdptr, virt_to_bus(mp->rx_cmds));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* put a branch at the end of the tx command list */
+    cp = mp->tx_cmds + NCMDS_TX * N_TX_RING;
+    cp->command = cpu_to_le16(DBDMA_NOP + BR_ALWAYS);
+    cp->cmd_dep = cpu_to_le32(virt_to_bus(mp->tx_cmds));
+
+    /* reset tx dma */
+    out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    out_le32(&td->cmdptr, virt_to_bus(mp->tx_cmds));
+    mp->tx_fill = 0;
+    mp->tx_empty = 0;
+    mp->tx_fullup = 0;
+    mp->tx_active = 0;
+    mp->tx_bad_runt = 0;
+
+    /* turn it on! */
+    out_8(&mb->maccc, mp->maccc);
+    /* enable all interrupts except receive interrupts */
+    out_8(&mb->imr, RCVINT);
+
+    return 0;
+}
+
+static int mace_close(struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
+    volatile struct dbdma_regs __iomem *td = mp->tx_dma;
+
+    /* disable rx and tx */
+    out_8(&mb->maccc, 0);
+    out_8(&mb->imr, 0xff);		/* disable all intrs */
+
+    /* disable rx and tx dma */
+    rd->control = cpu_to_le32((RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+    td->control = cpu_to_le32((RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+
+    mace_clean_rings(mp);
+
+    return 0;
+}
+
+static inline void mace_set_timeout(struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+
+    if (mp->timeout_active)
+	del_timer(&mp->tx_timeout);
+    mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+    add_timer(&mp->tx_timeout);
+    mp->timeout_active = 1;
+}
+
+static netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct dbdma_regs __iomem *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    unsigned long flags;
+    int fill, next, len;
+
+    /* see if there's a free slot in the tx ring */
+    spin_lock_irqsave(&mp->lock, flags);
+    fill = mp->tx_fill;
+    next = fill + 1;
+    if (next >= N_TX_RING)
+	next = 0;
+    if (next == mp->tx_empty) {
+	netif_stop_queue(dev);
+	mp->tx_fullup = 1;
+	spin_unlock_irqrestore(&mp->lock, flags);
+	return NETDEV_TX_BUSY;		/* can't take it at the moment */
+    }
+    spin_unlock_irqrestore(&mp->lock, flags);
+
+    /* partially fill in the dma command block */
+    len = skb->len;
+    if (len > ETH_FRAME_LEN) {
+	printk(KERN_DEBUG "mace: xmit frame too long (%d)\n", len);
+	len = ETH_FRAME_LEN;
+    }
+    mp->tx_bufs[fill] = skb;
+    cp = mp->tx_cmds + NCMDS_TX * fill;
+    cp->req_count = cpu_to_le16(len);
+    cp->phy_addr = cpu_to_le32(virt_to_bus(skb->data));
+
+    np = mp->tx_cmds + NCMDS_TX * next;
+    out_le16(&np->command, DBDMA_STOP);
+
+    /* poke the tx dma channel */
+    spin_lock_irqsave(&mp->lock, flags);
+    mp->tx_fill = next;
+    if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) {
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, OUTPUT_LAST);
+	out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	++mp->tx_active;
+	mace_set_timeout(dev);
+    }
+    if (++next >= N_TX_RING)
+	next = 0;
+    if (next == mp->tx_empty)
+	netif_stop_queue(dev);
+    spin_unlock_irqrestore(&mp->lock, flags);
+
+    return NETDEV_TX_OK;
+}
+
+static void mace_set_multicast(struct net_device *dev)
+{
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    int i;
+    u32 crc;
+    unsigned long flags;
+
+    spin_lock_irqsave(&mp->lock, flags);
+    mp->maccc &= ~PROM;
+    if (dev->flags & IFF_PROMISC) {
+	mp->maccc |= PROM;
+    } else {
+	unsigned char multicast_filter[8];
+	struct netdev_hw_addr *ha;
+
+	if (dev->flags & IFF_ALLMULTI) {
+	    for (i = 0; i < 8; i++)
+		multicast_filter[i] = 0xff;
+	} else {
+	    for (i = 0; i < 8; i++)
+		multicast_filter[i] = 0;
+	    netdev_for_each_mc_addr(ha, dev) {
+	        crc = ether_crc_le(6, ha->addr);
+		i = crc >> 26;	/* bit number in multicast_filter */
+		multicast_filter[i >> 3] |= 1 << (i & 7);
+	    }
+	}
+#if 0
+	printk("Multicast filter :");
+	for (i = 0; i < 8; i++)
+	    printk("%02x ", multicast_filter[i]);
+	printk("\n");
+#endif
+
+	if (mp->chipid == BROKEN_ADDRCHG_REV)
+	    out_8(&mb->iac, LOGADDR);
+	else {
+	    out_8(&mb->iac, ADDRCHG | LOGADDR);
+	    while ((in_8(&mb->iac) & ADDRCHG) != 0)
+		;
+	}
+	for (i = 0; i < 8; ++i)
+	    out_8(&mb->ladrf, multicast_filter[i]);
+	if (mp->chipid != BROKEN_ADDRCHG_REV)
+	    out_8(&mb->iac, 0);
+    }
+    /* reset maccc */
+    out_8(&mb->maccc, mp->maccc);
+    spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev)
+{
+    volatile struct mace __iomem *mb = mp->mace;
+    static int mace_babbles, mace_jabbers;
+
+    if (intr & MPCO)
+	dev->stats.rx_missed_errors += 256;
+    dev->stats.rx_missed_errors += in_8(&mb->mpc);   /* reading clears it */
+    if (intr & RNTPCO)
+	dev->stats.rx_length_errors += 256;
+    dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
+    if (intr & CERR)
+	++dev->stats.tx_heartbeat_errors;
+    if (intr & BABBLE)
+	if (mace_babbles++ < 4)
+	    printk(KERN_DEBUG "mace: babbling transmitter\n");
+    if (intr & JABBER)
+	if (mace_jabbers++ < 4)
+	    printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
+{
+    struct net_device *dev = (struct net_device *) dev_id;
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct mace __iomem *mb = mp->mace;
+    volatile struct dbdma_regs __iomem *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int intr, fs, i, stat, x;
+    int xcount, dstat;
+    unsigned long flags;
+    /* static int mace_last_fs, mace_last_xcount; */
+
+    spin_lock_irqsave(&mp->lock, flags);
+    intr = in_8(&mb->ir);		/* read interrupt register */
+    in_8(&mb->xmtrc);			/* get retries */
+    mace_handle_misc_intrs(mp, intr, dev);
+
+    i = mp->tx_empty;
+    while (in_8(&mb->pr) & XMTSV) {
+	del_timer(&mp->tx_timeout);
+	mp->timeout_active = 0;
+	/*
+	 * Clear any interrupt indication associated with this status
+	 * word.  This appears to unlatch any error indication from
+	 * the DMA controller.
+	 */
+	intr = in_8(&mb->ir);
+	if (intr != 0)
+	    mace_handle_misc_intrs(mp, intr, dev);
+	if (mp->tx_bad_runt) {
+	    fs = in_8(&mb->xmtfs);
+	    mp->tx_bad_runt = 0;
+	    out_8(&mb->xmtfc, AUTO_PAD_XMIT);
+	    continue;
+	}
+	dstat = le32_to_cpu(td->status);
+	/* stop DMA controller */
+	out_le32(&td->control, RUN << 16);
+	/*
+	 * xcount is the number of complete frames which have been
+	 * written to the fifo but for which status has not been read.
+	 */
+	xcount = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK;
+	if (xcount == 0 || (dstat & DEAD)) {
+	    /*
+	     * If a packet was aborted before the DMA controller has
+	     * finished transferring it, it seems that there are 2 bytes
+	     * which are stuck in some buffer somewhere.  These will get
+	     * transmitted as soon as we read the frame status (which
+	     * reenables the transmit data transfer request).  Turning
+	     * off the DMA controller and/or resetting the MACE doesn't
+	     * help.  So we disable auto-padding and FCS transmission
+	     * so the two bytes will only be a runt packet which should
+	     * be ignored by other stations.
+	     */
+	    out_8(&mb->xmtfc, DXMTFCS);
+	}
+	fs = in_8(&mb->xmtfs);
+	if ((fs & XMTSV) == 0) {
+	    printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
+		   fs, xcount, dstat);
+	    mace_reset(dev);
+		/*
+		 * XXX mace likes to hang the machine after a xmtfs error.
+		 * This is hard to reproduce, resetting *may* help
+		 */
+	}
+	cp = mp->tx_cmds + NCMDS_TX * i;
+	stat = le16_to_cpu(cp->xfer_status);
+	if ((fs & (UFLO|LCOL|LCAR|RTRY)) || (dstat & DEAD) || xcount == 0) {
+	    /*
+	     * Check whether there were in fact 2 bytes written to
+	     * the transmit FIFO.
+	     */
+	    udelay(1);
+	    x = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK;
+	    if (x != 0) {
+		/* there were two bytes with an end-of-packet indication */
+		mp->tx_bad_runt = 1;
+		mace_set_timeout(dev);
+	    } else {
+		/*
+		 * Either there weren't the two bytes buffered up, or they
+		 * didn't have an end-of-packet indication.
+		 * We flush the transmit FIFO just in case (by setting the
+		 * XMTFWU bit with the transmitter disabled).
+		 */
+		out_8(&mb->maccc, in_8(&mb->maccc) & ~ENXMT);
+		out_8(&mb->fifocc, in_8(&mb->fifocc) | XMTFWU);
+		udelay(1);
+		out_8(&mb->maccc, in_8(&mb->maccc) | ENXMT);
+		out_8(&mb->xmtfc, AUTO_PAD_XMIT);
+	    }
+	}
+	/* dma should have finished */
+	if (i == mp->tx_fill) {
+	    printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n",
+		   fs, xcount, dstat);
+	    continue;
+	}
+	/* Update stats */
+	if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+	    ++dev->stats.tx_errors;
+	    if (fs & LCAR)
+		++dev->stats.tx_carrier_errors;
+	    if (fs & (UFLO|LCOL|RTRY))
+		++dev->stats.tx_aborted_errors;
+	} else {
+	    dev->stats.tx_bytes += mp->tx_bufs[i]->len;
+	    ++dev->stats.tx_packets;
+	}
+	dev_kfree_skb_irq(mp->tx_bufs[i]);
+	--mp->tx_active;
+	if (++i >= N_TX_RING)
+	    i = 0;
+#if 0
+	mace_last_fs = fs;
+	mace_last_xcount = xcount;
+#endif
+    }
+
+    if (i != mp->tx_empty) {
+	mp->tx_fullup = 0;
+	netif_wake_queue(dev);
+    }
+    mp->tx_empty = i;
+    i += mp->tx_active;
+    if (i >= N_TX_RING)
+	i -= N_TX_RING;
+    if (!mp->tx_bad_runt && i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE) {
+	do {
+	    /* set up the next one */
+	    cp = mp->tx_cmds + NCMDS_TX * i;
+	    out_le16(&cp->xfer_status, 0);
+	    out_le16(&cp->command, OUTPUT_LAST);
+	    ++mp->tx_active;
+	    if (++i >= N_TX_RING)
+		i = 0;
+	} while (i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE);
+	out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	mace_set_timeout(dev);
+    }
+    spin_unlock_irqrestore(&mp->lock, flags);
+    return IRQ_HANDLED;
+}
+
+static void mace_tx_timeout(struct timer_list *t)
+{
+    struct mace_data *mp = from_timer(mp, t, tx_timeout);
+    struct net_device *dev = macio_get_drvdata(mp->mdev);
+    volatile struct mace __iomem *mb = mp->mace;
+    volatile struct dbdma_regs __iomem *td = mp->tx_dma;
+    volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp;
+    unsigned long flags;
+    int i;
+
+    spin_lock_irqsave(&mp->lock, flags);
+    mp->timeout_active = 0;
+    if (mp->tx_active == 0 && !mp->tx_bad_runt)
+	goto out;
+
+    /* update various counters */
+    mace_handle_misc_intrs(mp, in_8(&mb->ir), dev);
+
+    cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
+
+    /* turn off both tx and rx and reset the chip */
+    out_8(&mb->maccc, 0);
+    printk(KERN_ERR "mace: transmit timeout - resetting\n");
+    dbdma_reset(td);
+    mace_reset(dev);
+
+    /* restart rx dma */
+    cp = bus_to_virt(le32_to_cpu(rd->cmdptr));
+    dbdma_reset(rd);
+    out_le16(&cp->xfer_status, 0);
+    out_le32(&rd->cmdptr, virt_to_bus(cp));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* fix up the transmit side */
+    i = mp->tx_empty;
+    mp->tx_active = 0;
+    ++dev->stats.tx_errors;
+    if (mp->tx_bad_runt) {
+	mp->tx_bad_runt = 0;
+    } else if (i != mp->tx_fill) {
+	dev_kfree_skb(mp->tx_bufs[i]);
+	if (++i >= N_TX_RING)
+	    i = 0;
+	mp->tx_empty = i;
+    }
+    mp->tx_fullup = 0;
+    netif_wake_queue(dev);
+    if (i != mp->tx_fill) {
+	cp = mp->tx_cmds + NCMDS_TX * i;
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, OUTPUT_LAST);
+	out_le32(&td->cmdptr, virt_to_bus(cp));
+	out_le32(&td->control, (RUN << 16) | RUN);
+	++mp->tx_active;
+	mace_set_timeout(dev);
+    }
+
+    /* turn it back on */
+    out_8(&mb->imr, RCVINT);
+    out_8(&mb->maccc, mp->maccc);
+
+out:
+    spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
+{
+    struct net_device *dev = (struct net_device *) dev_id;
+    struct mace_data *mp = netdev_priv(dev);
+    volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    int i, nb, stat, next;
+    struct sk_buff *skb;
+    unsigned frame_status;
+    static int mace_lost_status;
+    unsigned char *data;
+    unsigned long flags;
+
+    spin_lock_irqsave(&mp->lock, flags);
+    for (i = mp->rx_empty; i != mp->rx_fill; ) {
+	cp = mp->rx_cmds + i;
+	stat = le16_to_cpu(cp->xfer_status);
+	if ((stat & ACTIVE) == 0) {
+	    next = i + 1;
+	    if (next >= N_RX_RING)
+		next = 0;
+	    np = mp->rx_cmds + next;
+	    if (next != mp->rx_fill &&
+		(le16_to_cpu(np->xfer_status) & ACTIVE) != 0) {
+		printk(KERN_DEBUG "mace: lost a status word\n");
+		++mace_lost_status;
+	    } else
+		break;
+	}
+	nb = le16_to_cpu(cp->req_count) - le16_to_cpu(cp->res_count);
+	out_le16(&cp->command, DBDMA_STOP);
+	/* got a packet, have a look at it */
+	skb = mp->rx_bufs[i];
+	if (!skb) {
+	    ++dev->stats.rx_dropped;
+	} else if (nb > 8) {
+	    data = skb->data;
+	    frame_status = (data[nb-3] << 8) + data[nb-4];
+	    if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
+		++dev->stats.rx_errors;
+		if (frame_status & RS_OFLO)
+		    ++dev->stats.rx_over_errors;
+		if (frame_status & RS_FRAMERR)
+		    ++dev->stats.rx_frame_errors;
+		if (frame_status & RS_FCSERR)
+		    ++dev->stats.rx_crc_errors;
+	    } else {
+		/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
+		 * FCS on frames with 802.3 headers. This means that Ethernet
+		 * frames have 8 extra octets at the end, while 802.3 frames
+		 * have only 4. We need to correctly account for this. */
+		if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
+		    nb -= 4;
+		else	/* Ethernet header; mace includes FCS */
+		    nb -= 8;
+		skb_put(skb, nb);
+		skb->protocol = eth_type_trans(skb, dev);
+		dev->stats.rx_bytes += skb->len;
+		netif_rx(skb);
+		mp->rx_bufs[i] = NULL;
+		++dev->stats.rx_packets;
+	    }
+	} else {
+	    ++dev->stats.rx_errors;
+	    ++dev->stats.rx_length_errors;
+	}
+
+	/* advance to next */
+	if (++i >= N_RX_RING)
+	    i = 0;
+    }
+    mp->rx_empty = i;
+
+    i = mp->rx_fill;
+    for (;;) {
+	next = i + 1;
+	if (next >= N_RX_RING)
+	    next = 0;
+	if (next == mp->rx_empty)
+	    break;
+	cp = mp->rx_cmds + i;
+	skb = mp->rx_bufs[i];
+	if (!skb) {
+	    skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
+	    if (skb) {
+		skb_reserve(skb, 2);
+		mp->rx_bufs[i] = skb;
+	    }
+	}
+	cp->req_count = cpu_to_le16(RX_BUFLEN);
+	data = skb? skb->data: dummy_buf;
+	cp->phy_addr = cpu_to_le32(virt_to_bus(data));
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+#if 0
+	if ((le32_to_cpu(rd->status) & ACTIVE) != 0) {
+	    out_le32(&rd->control, (PAUSE << 16) | PAUSE);
+	    while ((in_le32(&rd->status) & ACTIVE) != 0)
+		;
+	}
+#endif
+	i = next;
+    }
+    if (i != mp->rx_fill) {
+	out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE));
+	mp->rx_fill = i;
+    }
+    spin_unlock_irqrestore(&mp->lock, flags);
+    return IRQ_HANDLED;
+}
+
+static const struct of_device_id mace_match[] =
+{
+	{
+	.name 		= "mace",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE (of, mace_match);
+
+static struct macio_driver mace_driver =
+{
+	.driver = {
+		.name 		= "mace",
+		.owner		= THIS_MODULE,
+		.of_match_table	= mace_match,
+	},
+	.probe		= mace_probe,
+	.remove		= mace_remove,
+};
+
+
+static int __init mace_init(void)
+{
+	return macio_register_driver(&mace_driver);
+}
+
+static void __exit mace_cleanup(void)
+{
+	macio_unregister_driver(&mace_driver);
+
+	kfree(dummy_buf);
+	dummy_buf = NULL;
+}
+
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac MACE driver.");
+module_param(port_aaui, int, 0);
+MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
+MODULE_LICENSE("GPL");
+
+module_init(mace_init);
+module_exit(mace_cleanup);
diff --git a/drivers/net/ethernet/apple/mace.h b/drivers/net/ethernet/apple/mace.h
new file mode 100644
index 0000000..30b7ec0
--- /dev/null
+++ b/drivers/net/ethernet/apple/mace.h
@@ -0,0 +1,173 @@
+/*
+ * mace.h - definitions for the registers in the Am79C940 MACE
+ * (Medium Access Control for Ethernet) controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+
+#define REG(x)	volatile unsigned char x; char x ## _pad[15]
+
+struct mace {
+	REG(rcvfifo);		/* receive FIFO */
+	REG(xmtfifo);		/* transmit FIFO */
+	REG(xmtfc);		/* transmit frame control */
+	REG(xmtfs);		/* transmit frame status */
+	REG(xmtrc);		/* transmit retry count */
+	REG(rcvfc);		/* receive frame control */
+	REG(rcvfs);		/* receive frame status (4 bytes) */
+	REG(fifofc);		/* FIFO frame count */
+	REG(ir);		/* interrupt register */
+	REG(imr);		/* interrupt mask register */
+	REG(pr);		/* poll register */
+	REG(biucc);		/* bus interface unit config control */
+	REG(fifocc);		/* FIFO configuration control */
+	REG(maccc);		/* medium access control config control */
+	REG(plscc);		/* phys layer signalling config control */
+	REG(phycc);		/* physical configuration control */
+	REG(chipid_lo);		/* chip ID, lsb */
+	REG(chipid_hi);		/* chip ID, msb */
+	REG(iac);		/* internal address config */
+	REG(reg19);
+	REG(ladrf);		/* logical address filter (8 bytes) */
+	REG(padr);		/* physical address (6 bytes) */
+	REG(reg22);
+	REG(reg23);
+	REG(mpc);		/* missed packet count (clears when read) */
+	REG(reg25);
+	REG(rntpc);		/* runt packet count (clears when read) */
+	REG(rcvcc);		/* recv collision count (clears when read) */
+	REG(reg28);
+	REG(utr);		/* user test reg */
+	REG(reg30);
+	REG(reg31);
+};
+
+/* Bits in XMTFC */
+#define DRTRY		0x80	/* don't retry transmission after collision */
+#define DXMTFCS		0x08	/* don't append FCS to transmitted frame */
+#define AUTO_PAD_XMIT	0x01	/* auto-pad short packets on transmission */
+
+/* Bits in XMTFS: only valid when XMTSV is set in PR and XMTFS */
+#define XMTSV		0x80	/* transmit status (i.e. XMTFS) valid */
+#define UFLO		0x40	/* underflow - xmit fifo ran dry */
+#define LCOL		0x20	/* late collision (transmission aborted) */
+#define MORE		0x10	/* 2 or more retries needed to xmit frame */
+#define ONE		0x08	/* 1 retry needed to xmit frame */
+#define DEFER		0x04	/* MACE had to defer xmission (enet busy) */
+#define LCAR		0x02	/* loss of carrier (transmission aborted) */
+#define RTRY		0x01	/* too many retries (transmission aborted) */
+
+/* Bits in XMTRC: only valid when XMTSV is set in PR (and XMTFS) */
+#define EXDEF		0x80	/* had to defer for excessive time */
+#define RETRY_MASK	0x0f	/* number of retries (0 - 15) */
+
+/* Bits in RCVFC */
+#define LLRCV		0x08	/* low latency receive: early DMA request */
+#define M_RBAR		0x04	/* sets function of EAM/R pin */
+#define AUTO_STRIP_RCV	0x01	/* auto-strip short LLC frames on recv */
+
+/*
+ * Bits in RCVFS.  After a frame is received, four bytes of status
+ * are automatically read from this register and appended to the frame
+ * data in memory.  These are:
+ * Byte 0 and 1: message byte count and frame status
+ * Byte 2: runt packet count
+ * Byte 3: receive collision count
+ */
+#define RS_OFLO		0x8000	/* receive FIFO overflowed */
+#define RS_CLSN		0x4000	/* received frame suffered (late) collision */
+#define RS_FRAMERR	0x2000	/* framing error flag */
+#define RS_FCSERR	0x1000	/* frame had FCS error */
+#define RS_COUNT	0x0fff	/* mask for byte count field */
+
+/* Bits (fields) in FIFOFC */
+#define RCVFC_SH	4	/* receive frame count in FIFO */
+#define RCVFC_MASK	0x0f
+#define XMTFC_SH	0	/* transmit frame count in FIFO */
+#define XMTFC_MASK	0x0f
+
+/*
+ * Bits in IR and IMR.  The IR clears itself when read.
+ * Setting a bit in the IMR will disable the corresponding interrupt.
+ */
+#define JABBER		0x80	/* jabber error - 10baseT xmission too long */
+#define BABBLE		0x40	/* babble - xmitter xmitting for too long */
+#define CERR		0x20	/* collision err - no SQE test (heartbeat) */
+#define RCVCCO		0x10	/* RCVCC overflow */
+#define RNTPCO		0x08	/* RNTPC overflow */
+#define MPCO		0x04	/* MPC overflow */
+#define RCVINT		0x02	/* receive interrupt */
+#define XMTINT		0x01	/* transmitter interrupt */
+
+/* Bits in PR */
+#define XMTSV		0x80	/* XMTFS valid (same as in XMTFS) */
+#define TDTREQ		0x40	/* set when xmit fifo is requesting data */
+#define RDTREQ		0x20	/* set when recv fifo requests data xfer */
+
+/* Bits in BIUCC */
+#define BSWP		0x40	/* byte swap, i.e. big-endian bus */
+#define XMTSP_4		0x00	/* start xmitting when 4 bytes in FIFO */
+#define XMTSP_16	0x10	/* start xmitting when 16 bytes in FIFO */
+#define XMTSP_64	0x20	/* start xmitting when 64 bytes in FIFO */
+#define XMTSP_112	0x30	/* start xmitting when 112 bytes in FIFO */
+#define SWRST		0x01	/* software reset */
+
+/* Bits in FIFOCC */
+#define XMTFW_8		0x00	/* xmit fifo watermark = 8 words free */
+#define XMTFW_16	0x40	/*  16 words free */
+#define XMTFW_32	0x80	/*  32 words free */
+#define RCVFW_16	0x00	/* recv fifo watermark = 16 bytes avail */
+#define RCVFW_32	0x10	/*  32 bytes avail */
+#define RCVFW_64	0x20	/*  64 bytes avail */
+#define XMTFWU		0x08	/* xmit fifo watermark update enable */
+#define RCVFWU		0x04	/* recv fifo watermark update enable */
+#define XMTBRST		0x02	/* enable transmit burst mode */
+#define RCVBRST		0x01	/* enable receive burst mode */
+
+/* Bits in MACCC */
+#define PROM		0x80	/* promiscuous mode */
+#define DXMT2PD		0x40	/* disable xmit two-part deferral algorithm */
+#define EMBA		0x20	/* enable modified backoff algorithm */
+#define DRCVPA		0x08	/* disable receiving physical address */
+#define DRCVBC		0x04	/* disable receiving broadcasts */
+#define ENXMT		0x02	/* enable transmitter */
+#define ENRCV		0x01	/* enable receiver */
+
+/* Bits in PLSCC */
+#define XMTSEL		0x08	/* select DO+/DO- state when idle */
+#define PORTSEL_AUI	0x00	/* select AUI port */
+#define PORTSEL_10T	0x02	/* select 10Base-T port */
+#define PORTSEL_DAI	0x04	/* select DAI port */
+#define PORTSEL_GPSI	0x06	/* select GPSI port */
+#define ENPLSIO		0x01	/* enable optional PLS I/O pins */
+
+/* Bits in PHYCC */
+#define LNKFL		0x80	/* reports 10Base-T link failure */
+#define DLNKTST		0x40	/* disable 10Base-T link test */
+#define REVPOL		0x20	/* 10Base-T receiver polarity reversed */
+#define DAPC		0x10	/* disable auto receiver polarity correction */
+#define LRT		0x08	/* low receive threshold for long links */
+#define ASEL		0x04	/* auto-select AUI or 10Base-T port */
+#define RWAKE		0x02	/* remote wake function */
+#define AWAKE		0x01	/* auto wake function */
+
+/* Bits in IAC */
+#define ADDRCHG		0x80	/* request address change */
+#define PHYADDR		0x04	/* access physical address */
+#define LOGADDR		0x02	/* access multicast filter */
+
+/* Bits in UTR */
+#define RTRE		0x80	/* reserved test register enable. DON'T SET. */
+#define RTRD		0x40	/* reserved test register disable.  Sticky */
+#define RPAC		0x20	/* accept runt packets */
+#define FCOLL		0x10	/* force collision */
+#define RCVFCSE		0x08	/* receive FCS enable */
+#define LOOP_NONE	0x00	/* no loopback */
+#define LOOP_EXT	0x02	/* external loopback */
+#define LOOP_INT	0x04	/* internal loopback, excludes MENDEC */
+#define LOOP_MENDEC	0x06	/* internal loopback, includes MENDEC */
diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c
new file mode 100644
index 0000000..376f2c2
--- /dev/null
+++ b/drivers/net/ethernet/apple/macmace.c
@@ -0,0 +1,770 @@
+/*
+ *	Driver for the Macintosh 68K onboard MACE controller with PSC
+ *	driven DMA. The MACE driver code is derived from mace.c. The
+ *	Mac68k theory of operation is courtesy of the MacBSD wizards.
+ *
+ *	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.
+ *
+ *	Copyright (C) 1996 Paul Mackerras.
+ *	Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *	Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
+ *
+ *	Copyright (C) 2007 Finn Thain
+ *
+ *	Converted to DMA API, converted to unified driver model,
+ *	sync'd some routines with mace.c and fixed various bugs.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/crc32.h>
+#include <linux/bitrev.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/macints.h>
+#include <asm/mac_psc.h>
+#include <asm/page.h>
+#include "mace.h"
+
+static char mac_mace_string[] = "macmace";
+
+#define N_TX_BUFF_ORDER	0
+#define N_TX_RING	(1 << N_TX_BUFF_ORDER)
+#define N_RX_BUFF_ORDER	3
+#define N_RX_RING	(1 << N_RX_BUFF_ORDER)
+
+#define TX_TIMEOUT	HZ
+
+#define MACE_BUFF_SIZE	0x800
+
+/* Chip rev needs workaround on HW & multicast addr change */
+#define BROKEN_ADDRCHG_REV	0x0941
+
+/* The MACE is simply wired down on a Mac68K box */
+
+#define MACE_BASE	(void *)(0x50F1C000)
+#define MACE_PROM	(void *)(0x50F08001)
+
+struct mace_data {
+	volatile struct mace *mace;
+	unsigned char *tx_ring;
+	dma_addr_t tx_ring_phys;
+	unsigned char *rx_ring;
+	dma_addr_t rx_ring_phys;
+	int dma_intr;
+	int rx_slot, rx_tail;
+	int tx_slot, tx_sloti, tx_count;
+	int chipid;
+	struct device *device;
+};
+
+struct mace_frame {
+	u8	rcvcnt;
+	u8	pad1;
+	u8	rcvsts;
+	u8	pad2;
+	u8	rntpc;
+	u8	pad3;
+	u8	rcvcc;
+	u8	pad4;
+	u32	pad5;
+	u32	pad6;
+	u8	data[1];
+	/* And frame continues.. */
+};
+
+#define PRIV_BYTES	sizeof(struct mace_data)
+
+static int mace_open(struct net_device *dev);
+static int mace_close(struct net_device *dev);
+static netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static void mace_set_multicast(struct net_device *dev);
+static int mace_set_address(struct net_device *dev, void *addr);
+static void mace_reset(struct net_device *dev);
+static irqreturn_t mace_interrupt(int irq, void *dev_id);
+static irqreturn_t mace_dma_intr(int irq, void *dev_id);
+static void mace_tx_timeout(struct net_device *dev);
+static void __mace_set_address(struct net_device *dev, void *addr);
+
+/*
+ * Load a receive DMA channel with a base address and ring length
+ */
+
+static void mace_load_rxdma_base(struct net_device *dev, int set)
+{
+	struct mace_data *mp = netdev_priv(dev);
+
+	psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
+	psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys);
+	psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING);
+	psc_write_word(PSC_ENETRD_CMD + set, 0x9800);
+	mp->rx_tail = 0;
+}
+
+/*
+ * Reset the receive DMA subsystem
+ */
+
+static void mace_rxdma_reset(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mace = mp->mace;
+	u8 maccc = mace->maccc;
+
+	mace->maccc = maccc & ~ENRCV;
+
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	mace_load_rxdma_base(dev, 0x00);
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	mace_load_rxdma_base(dev, 0x10);
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+	mace->maccc = maccc;
+	mp->rx_slot = 0;
+
+	psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800);
+	psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800);
+}
+
+/*
+ * Reset the transmit DMA subsystem
+ */
+
+static void mace_txdma_reset(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mace = mp->mace;
+	u8 maccc;
+
+	psc_write_word(PSC_ENETWR_CTL, 0x8800);
+
+	maccc = mace->maccc;
+	mace->maccc = maccc & ~ENXMT;
+
+	mp->tx_slot = mp->tx_sloti = 0;
+	mp->tx_count = N_TX_RING;
+
+	psc_write_word(PSC_ENETWR_CTL, 0x0400);
+	mace->maccc = maccc;
+}
+
+/*
+ * Disable DMA
+ */
+
+static void mace_dma_off(struct net_device *dev)
+{
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	psc_write_word(PSC_ENETRD_CTL, 0x1000);
+	psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100);
+	psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100);
+
+	psc_write_word(PSC_ENETWR_CTL, 0x8800);
+	psc_write_word(PSC_ENETWR_CTL, 0x1000);
+	psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100);
+	psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100);
+}
+
+static const struct net_device_ops mace_netdev_ops = {
+	.ndo_open		= mace_open,
+	.ndo_stop		= mace_close,
+	.ndo_start_xmit		= mace_xmit_start,
+	.ndo_tx_timeout		= mace_tx_timeout,
+	.ndo_set_rx_mode	= mace_set_multicast,
+	.ndo_set_mac_address	= mace_set_address,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+/*
+ * Not really much of a probe. The hardware table tells us if this
+ * model of Macintrash has a MACE (AV macintoshes)
+ */
+
+static int mace_probe(struct platform_device *pdev)
+{
+	int j;
+	struct mace_data *mp;
+	unsigned char *addr;
+	struct net_device *dev;
+	unsigned char checksum = 0;
+	int err;
+
+	dev = alloc_etherdev(PRIV_BYTES);
+	if (!dev)
+		return -ENOMEM;
+
+	mp = netdev_priv(dev);
+
+	mp->device = &pdev->dev;
+	platform_set_drvdata(pdev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	dev->base_addr = (u32)MACE_BASE;
+	mp->mace = MACE_BASE;
+
+	dev->irq = IRQ_MAC_MACE;
+	mp->dma_intr = IRQ_MAC_MACE_DMA;
+
+	mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo;
+
+	/*
+	 * The PROM contains 8 bytes which total 0xFF when XOR'd
+	 * together. Due to the usual peculiar apple brain damage
+	 * the bytes are spaced out in a strange boundary and the
+	 * bits are reversed.
+	 */
+
+	addr = MACE_PROM;
+
+	for (j = 0; j < 6; ++j) {
+		u8 v = bitrev8(addr[j<<4]);
+		checksum ^= v;
+		dev->dev_addr[j] = v;
+	}
+	for (; j < 8; ++j) {
+		checksum ^= bitrev8(addr[j<<4]);
+	}
+
+	if (checksum != 0xFF) {
+		free_netdev(dev);
+		return -ENODEV;
+	}
+
+	dev->netdev_ops		= &mace_netdev_ops;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+
+	pr_info("Onboard MACE, hardware address %pM, chip revision 0x%04X\n",
+		dev->dev_addr, mp->chipid);
+
+	err = register_netdev(dev);
+	if (!err)
+		return 0;
+
+	free_netdev(dev);
+	return err;
+}
+
+/*
+ * Reset the chip.
+ */
+
+static void mace_reset(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	int i;
+
+	/* soft-reset the chip */
+	i = 200;
+	while (--i) {
+		mb->biucc = SWRST;
+		if (mb->biucc & SWRST) {
+			udelay(10);
+			continue;
+		}
+		break;
+	}
+	if (!i) {
+		printk(KERN_ERR "macmace: cannot reset chip!\n");
+		return;
+	}
+
+	mb->maccc = 0;	/* turn off tx, rx */
+	mb->imr = 0xFF;	/* disable all intrs for now */
+	i = mb->ir;
+
+	mb->biucc = XMTSP_64;
+	mb->utr = RTRD;
+	mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU;
+
+	mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+	mb->rcvfc = 0;
+
+	/* load up the hardware address */
+	__mace_set_address(dev, dev->dev_addr);
+
+	/* clear the multicast filter */
+	if (mp->chipid == BROKEN_ADDRCHG_REV)
+		mb->iac = LOGADDR;
+	else {
+		mb->iac = ADDRCHG | LOGADDR;
+		while ((mb->iac & ADDRCHG) != 0)
+			;
+	}
+	for (i = 0; i < 8; ++i)
+		mb->ladrf = 0;
+
+	/* done changing address */
+	if (mp->chipid != BROKEN_ADDRCHG_REV)
+		mb->iac = 0;
+
+	mb->plscc = PORTSEL_AUI;
+}
+
+/*
+ * Load the address on a mace controller.
+ */
+
+static void __mace_set_address(struct net_device *dev, void *addr)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	unsigned char *p = addr;
+	int i;
+
+	/* load up the hardware address */
+	if (mp->chipid == BROKEN_ADDRCHG_REV)
+		mb->iac = PHYADDR;
+	else {
+		mb->iac = ADDRCHG | PHYADDR;
+		while ((mb->iac & ADDRCHG) != 0)
+			;
+	}
+	for (i = 0; i < 6; ++i)
+		mb->padr = dev->dev_addr[i] = p[i];
+	if (mp->chipid != BROKEN_ADDRCHG_REV)
+		mb->iac = 0;
+}
+
+static int mace_set_address(struct net_device *dev, void *addr)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	unsigned long flags;
+	u8 maccc;
+
+	local_irq_save(flags);
+
+	maccc = mb->maccc;
+
+	__mace_set_address(dev, addr);
+
+	mb->maccc = maccc;
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+/*
+ * Open the Macintosh MACE. Most of this is playing with the DMA
+ * engine. The ethernet chip is quite friendly.
+ */
+
+static int mace_open(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+
+	/* reset the chip */
+	mace_reset(dev);
+
+	if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) {
+		printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) {
+		printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr);
+		free_irq(dev->irq, dev);
+		return -EAGAIN;
+	}
+
+	/* Allocate the DMA ring buffers */
+
+	mp->tx_ring = dma_alloc_coherent(mp->device,
+					 N_TX_RING * MACE_BUFF_SIZE,
+					 &mp->tx_ring_phys, GFP_KERNEL);
+	if (mp->tx_ring == NULL)
+		goto out1;
+
+	mp->rx_ring = dma_alloc_coherent(mp->device,
+					 N_RX_RING * MACE_BUFF_SIZE,
+					 &mp->rx_ring_phys, GFP_KERNEL);
+	if (mp->rx_ring == NULL)
+		goto out2;
+
+	mace_dma_off(dev);
+
+	/* Not sure what these do */
+
+	psc_write_word(PSC_ENETWR_CTL, 0x9000);
+	psc_write_word(PSC_ENETRD_CTL, 0x9000);
+	psc_write_word(PSC_ENETWR_CTL, 0x0400);
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+	mace_rxdma_reset(dev);
+	mace_txdma_reset(dev);
+
+	/* turn it on! */
+	mb->maccc = ENXMT | ENRCV;
+	/* enable all interrupts except receive interrupts */
+	mb->imr = RCVINT;
+	return 0;
+
+out2:
+	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+	                  mp->tx_ring, mp->tx_ring_phys);
+out1:
+	free_irq(dev->irq, dev);
+	free_irq(mp->dma_intr, dev);
+	return -ENOMEM;
+}
+
+/*
+ * Shut down the mace and its interrupt channel
+ */
+
+static int mace_close(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+
+	mb->maccc = 0;		/* disable rx and tx	 */
+	mb->imr = 0xFF;		/* disable all irqs	 */
+	mace_dma_off(dev);	/* disable rx and tx dma */
+
+	return 0;
+}
+
+/*
+ * Transmit a frame
+ */
+
+static netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	unsigned long flags;
+
+	/* Stop the queue since there's only the one buffer */
+
+	local_irq_save(flags);
+	netif_stop_queue(dev);
+	if (!mp->tx_count) {
+		printk(KERN_ERR "macmace: tx queue running but no free buffers.\n");
+		local_irq_restore(flags);
+		return NETDEV_TX_BUSY;
+	}
+	mp->tx_count--;
+	local_irq_restore(flags);
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	/* We need to copy into our xmit buffer to take care of alignment and caching issues */
+	skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
+
+	/* load the Tx DMA and fire it off */
+
+	psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32)  mp->tx_ring_phys);
+	psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len);
+	psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800);
+
+	mp->tx_slot ^= 0x10;
+
+	dev_kfree_skb(skb);
+
+	return NETDEV_TX_OK;
+}
+
+static void mace_set_multicast(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	int i;
+	u32 crc;
+	u8 maccc;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	maccc = mb->maccc;
+	mb->maccc &= ~PROM;
+
+	if (dev->flags & IFF_PROMISC) {
+		mb->maccc |= PROM;
+	} else {
+		unsigned char multicast_filter[8];
+		struct netdev_hw_addr *ha;
+
+		if (dev->flags & IFF_ALLMULTI) {
+			for (i = 0; i < 8; i++) {
+				multicast_filter[i] = 0xFF;
+			}
+		} else {
+			for (i = 0; i < 8; i++)
+				multicast_filter[i] = 0;
+			netdev_for_each_mc_addr(ha, dev) {
+				crc = ether_crc_le(6, ha->addr);
+				/* bit number in multicast_filter */
+				i = crc >> 26;
+				multicast_filter[i >> 3] |= 1 << (i & 7);
+			}
+		}
+
+		if (mp->chipid == BROKEN_ADDRCHG_REV)
+			mb->iac = LOGADDR;
+		else {
+			mb->iac = ADDRCHG | LOGADDR;
+			while ((mb->iac & ADDRCHG) != 0)
+				;
+		}
+		for (i = 0; i < 8; ++i)
+			mb->ladrf = multicast_filter[i];
+		if (mp->chipid != BROKEN_ADDRCHG_REV)
+			mb->iac = 0;
+	}
+
+	mb->maccc = maccc;
+	local_irq_restore(flags);
+}
+
+static void mace_handle_misc_intrs(struct net_device *dev, int intr)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	static int mace_babbles, mace_jabbers;
+
+	if (intr & MPCO)
+		dev->stats.rx_missed_errors += 256;
+	dev->stats.rx_missed_errors += mb->mpc;   /* reading clears it */
+	if (intr & RNTPCO)
+		dev->stats.rx_length_errors += 256;
+	dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+	if (intr & CERR)
+		++dev->stats.tx_heartbeat_errors;
+	if (intr & BABBLE)
+		if (mace_babbles++ < 4)
+			printk(KERN_DEBUG "macmace: babbling transmitter\n");
+	if (intr & JABBER)
+		if (mace_jabbers++ < 4)
+			printk(KERN_DEBUG "macmace: jabbering transceiver\n");
+}
+
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	int intr, fs;
+	unsigned long flags;
+
+	/* don't want the dma interrupt handler to fire */
+	local_irq_save(flags);
+
+	intr = mb->ir; /* read interrupt register */
+	mace_handle_misc_intrs(dev, intr);
+
+	if (intr & XMTINT) {
+		fs = mb->xmtfs;
+		if ((fs & XMTSV) == 0) {
+			printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs);
+			mace_reset(dev);
+			/*
+			 * XXX mace likes to hang the machine after a xmtfs error.
+			 * This is hard to reproduce, resetting *may* help
+			 */
+		}
+		/* dma should have finished */
+		if (!mp->tx_count) {
+			printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs);
+		}
+		/* Update stats */
+		if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+			++dev->stats.tx_errors;
+			if (fs & LCAR)
+				++dev->stats.tx_carrier_errors;
+			else if (fs & (UFLO|LCOL|RTRY)) {
+				++dev->stats.tx_aborted_errors;
+				if (mb->xmtfs & UFLO) {
+					dev->stats.tx_fifo_errors++;
+					mace_txdma_reset(dev);
+				}
+			}
+		}
+	}
+
+	if (mp->tx_count)
+		netif_wake_queue(dev);
+
+	local_irq_restore(flags);
+
+	return IRQ_HANDLED;
+}
+
+static void mace_tx_timeout(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* turn off both tx and rx and reset the chip */
+	mb->maccc = 0;
+	printk(KERN_ERR "macmace: transmit timeout - resetting\n");
+	mace_txdma_reset(dev);
+	mace_reset(dev);
+
+	/* restart rx dma */
+	mace_rxdma_reset(dev);
+
+	mp->tx_count = N_TX_RING;
+	netif_wake_queue(dev);
+
+	/* turn it on! */
+	mb->maccc = ENXMT | ENRCV;
+	/* enable all interrupts except receive interrupts */
+	mb->imr = RCVINT;
+
+	local_irq_restore(flags);
+}
+
+/*
+ * Handle a newly arrived frame
+ */
+
+static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
+{
+	struct sk_buff *skb;
+	unsigned int frame_status = mf->rcvsts;
+
+	if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
+		dev->stats.rx_errors++;
+		if (frame_status & RS_OFLO)
+			dev->stats.rx_fifo_errors++;
+		if (frame_status & RS_CLSN)
+			dev->stats.collisions++;
+		if (frame_status & RS_FRAMERR)
+			dev->stats.rx_frame_errors++;
+		if (frame_status & RS_FCSERR)
+			dev->stats.rx_crc_errors++;
+	} else {
+		unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
+
+		skb = netdev_alloc_skb(dev, frame_length + 2);
+		if (!skb) {
+			dev->stats.rx_dropped++;
+			return;
+		}
+		skb_reserve(skb, 2);
+		skb_put_data(skb, mf->data, frame_length);
+
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += frame_length;
+	}
+}
+
+/*
+ * The PSC has passed us a DMA interrupt event.
+ */
+
+static irqreturn_t mace_dma_intr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct mace_data *mp = netdev_priv(dev);
+	int left, head;
+	u16 status;
+	u32 baka;
+
+	/* Not sure what this does */
+
+	while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY));
+	if (!(baka & 0x60000000)) return IRQ_NONE;
+
+	/*
+	 * Process the read queue
+	 */
+
+	status = psc_read_word(PSC_ENETRD_CTL);
+
+	if (status & 0x2000) {
+		mace_rxdma_reset(dev);
+	} else if (status & 0x0100) {
+		psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100);
+
+		left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot);
+		head = N_RX_RING - left;
+
+		/* Loop through the ring buffer and process new packages */
+
+		while (mp->rx_tail < head) {
+			mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring
+				+ (mp->rx_tail * MACE_BUFF_SIZE)));
+			mp->rx_tail++;
+		}
+
+		/* If we're out of buffers in this ring then switch to */
+		/* the other set, otherwise just reactivate this one.  */
+
+		if (!left) {
+			mace_load_rxdma_base(dev, mp->rx_slot);
+			mp->rx_slot ^= 0x10;
+		} else {
+			psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800);
+		}
+	}
+
+	/*
+	 * Process the write queue
+	 */
+
+	status = psc_read_word(PSC_ENETWR_CTL);
+
+	if (status & 0x2000) {
+		mace_txdma_reset(dev);
+	} else if (status & 0x0100) {
+		psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100);
+		mp->tx_sloti ^= 0x10;
+		mp->tx_count++;
+	}
+	return IRQ_HANDLED;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Macintosh MACE ethernet driver");
+MODULE_ALIAS("platform:macmace");
+
+static int mac_mace_device_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct mace_data *mp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+
+	free_irq(dev->irq, dev);
+	free_irq(IRQ_MAC_MACE_DMA, dev);
+
+	dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE,
+	                  mp->rx_ring, mp->rx_ring_phys);
+	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+	                  mp->tx_ring, mp->tx_ring_phys);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+static struct platform_driver mac_mace_driver = {
+	.probe  = mace_probe,
+	.remove = mac_mace_device_remove,
+	.driver	= {
+		.name	= mac_mace_string,
+	},
+};
+
+module_platform_driver(mac_mace_driver);