--- linux/drivers/net/au1000_eth.c	2004-11-26 03:45:17.000000000 -0500
+++ linux/drivers/net/au1000_eth.c	2004-12-08 16:29:01.692514040 -0500
@@ -6,6 +6,8 @@
  * Copyright 2002 TimeSys Corp.
  * Added ethtool/mii-tool support,
  * Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
+ * Added NAPI support
+ * Copyright 2004 Charles Eidsness <charles@cooper-street.com>
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
@@ -57,6 +59,8 @@
 #include <asm/cpu.h>
 #include "au1000_eth.h"
 
+#define AU1000_ETH_NAPI		/* enable NAPI interrupt method */
+
 #ifdef AU1000_ETH_DEBUG
 static int au1000_debug = 5;
 #else
@@ -64,7 +68,11 @@
 #endif
 
 #define DRV_NAME	"au1000eth"
+#ifdef AU1000_ETH_NAPI
+#define DRV_VERSION	"1.5"
+#else
 #define DRV_VERSION	"1.4"
+#endif
 #define DRV_AUTHOR	"Pete Popov <ppopov@embeddedalley.com>"
 #define DRV_DESC	"Au1xxx on-chip Ethernet driver"
 
@@ -80,7 +88,11 @@
 static int au1000_open(struct net_device *);
 static int au1000_close(struct net_device *);
 static int au1000_tx(struct sk_buff *, struct net_device *);
+#ifdef AU1000_ETH_NAPI
+static int au1000_poll(struct net_device *dev, int *budget);
+#else
 static int au1000_rx(struct net_device *);
+#endif
 static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);
 static void au1000_tx_timeout(struct net_device *);
 static int au1000_set_config(struct net_device *dev, struct ifmap *map);
@@ -149,13 +161,6 @@
 	SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
 	SUPPORTED_Autoneg
 
-static char *phy_link[] = 
-{	"unknown", 
-	"10Base2", "10BaseT", 
-	"AUI",
-	"100BaseT", "100BaseTX", "100BaseFX"
-};
-
 int bcm_5201_init(struct net_device *dev, int phy_addr)
 {
 	s16 data;
@@ -1116,7 +1121,7 @@
 	if (aup->timer.function == &au1000_timer) {/* check if timer initted */
 		del_timer(&aup->timer);
 	}
-
+	
 	hard_stop(dev);
 	#ifdef CONFIG_BCM5222_DUAL_PHY
 	if (aup->mac_id != 0) {
@@ -1594,6 +1599,11 @@
 	dev->set_config = &au1000_set_config;
 	dev->tx_timeout = au1000_tx_timeout;
 	dev->watchdog_timeo = ETH_TX_TIMEOUT;
+#ifdef AU1000_ETH_NAPI
+	dev->poll = au1000_poll;
+	dev->weight = 16;
+#endif
+
 
 	/* 
 	 * The boot code uses the ethernet controller, so reset it to start 
@@ -1862,6 +1872,7 @@
  * the TX DONE bits.  This is a must if the irq is setup as
  * edge triggered.
  */
+#ifndef AU1000_ETH_NAPI
 static void au1000_tx_ack(struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -1884,7 +1895,7 @@
 		}
 	}
 }
-
+#endif
 
 /*
  * Au1000 transmit routine.
@@ -1965,9 +1976,79 @@
 
 }
 
+#ifdef AU1000_ETH_NAPI
+static int au1000_poll(struct net_device *dev, int *budget)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct sk_buff *skb;
+	int frmlen, rx_work_limit = dev->quota, received = 0;
+	char proc_tx, proc_rx;
+	db_dest_t *pDB;
+	volatile tx_dma_t *ptxd;
+	volatile rx_dma_t *prxd;
+
+	prxd = aup->rx_dma_ring[aup->rx_head];
+	ptxd = aup->tx_dma_ring[aup->tx_tail];
+	proc_tx = (ptxd->buff_stat & TX_T_DONE);
+	proc_rx = (prxd->buff_stat & RX_T_DONE) && (rx_work_limit > 0);
+	while (proc_tx || proc_rx) {
+		if (proc_rx) {
+			update_rx_stats(dev, prxd->status);
+			pDB = aup->rx_db_inuse[aup->rx_head];
+			if (!(prxd->status & RX_ERROR) && rx_work_limit > 0)
+			{
+				rx_work_limit--;
+				frmlen = (prxd->status & RX_FRAME_LEN_MASK);
+				frmlen -= 4;
+				skb = dev_alloc_skb(frmlen + 2);
+				if (skb == NULL) {
+					printk(KERN_ERR "%s: Memory squeeze," 
+						"dropping packet.\n",dev->name);
+					aup->stats.rx_dropped++;
+					continue;
+				}
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte IP header align */
+				eth_copy_and_sum(skb,
+					(unsigned char *)pDB->vaddr, frmlen, 0);
+				skb_put(skb, frmlen);
+
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_receive_skb(skb);	/* pass the packet to upper layers */
+				received++;
+			}
+			prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
+			aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);
+			au_sync();
+			dev->last_rx = jiffies;
+			prxd = aup->rx_dma_ring[aup->rx_head];
+		}
+		if(proc_tx) {
+			update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
+			ptxd->buff_stat &= ~TX_T_DONE;
+			ptxd->len = 0;
+			au_sync();
+			aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
+			ptxd = aup->tx_dma_ring[aup->tx_tail];
+			if (aup->tx_full) {
+				aup->tx_full = 0;
+				netif_wake_queue(dev);
+			}
+		}
+		proc_tx = (ptxd->buff_stat & TX_T_DONE);
+		proc_rx = (prxd->buff_stat & RX_T_DONE) && (rx_work_limit > 0);
+	}
+	dev->quota -=received;
+	*budget -= received;
+	netif_rx_complete(dev);
+	enable_irq(dev->irq);
+	return 0;
+}
+#endif
 /*
  * Au1000 receive routine.
  */
+#ifndef AU1000_ETH_NAPI
 static int au1000_rx(struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -1976,7 +2057,7 @@
 	u32 buff_stat, status;
 	db_dest_t *pDB;
 	u32	frmlen;
-
+	
 	if (au1000_debug > 5)
 		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
 
@@ -2042,11 +2123,31 @@
 	}
 	return 0;
 }
-
+#endif
 
 /*
  * Au1000 interrupt service routine.
  */
+#ifdef AU1000_ETH_NAPI
+static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
+		return IRQ_RETVAL(1);
+	}
+
+	if (netif_rx_schedule_prep(dev)) {
+		disable_irq_nosync(irq);
+		__netif_rx_schedule(dev);
+	} else {
+		printk("driver bug! interrupt while in poll\n");
+		disable_irq_nosync(irq);
+	}
+	return IRQ_RETVAL(1);
+}
+#else
 static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
@@ -2062,7 +2163,7 @@
 	au1000_tx_ack(dev);
 	return IRQ_RETVAL(1);
 }
-
+#endif
 
 /*
  * The Tx ring has been full longer than the watchdog timeout
@@ -2145,7 +2246,7 @@
 			return -EPERM;
 		mdio_write(dev, aup->phy_addr, data[1], data[2]);
 		return 0;
-	default:
+		default:
 		return -EOPNOTSUPP;
 	}
 }
