diff -Nru linux-2.6.8.1-davem269_4/drivers/net/Kconfig linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig
--- linux-2.6.8.1-davem269_4/drivers/net/Kconfig	2004-08-14 12:56:00.000000000 +0200
+++ linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig	2004-09-14 11:40:40.000000000 +0200
@@ -1534,6 +1550,22 @@
 	  and others, including the 83815 chip.
 	  More specific information and updates are available from
 	  <http://www.scyld.com/network/natsemi.html>.
+config NATSEMI_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on NATSEMI && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+	  information.
+
+	  If in doubt, say N.
 
 config NE2K_PCI
 	tristate "PCI NE2000 and clones support (see help)"

--- linux-2.6.9-rc1-plain/drivers/net/natsemi.c	2004-08-31 20:24:39.000000000 +0200
+++ linux-2.6.9-rc1-natsemi-napi/drivers/net/natsemi.c	2004-09-14 22:53:50.000000000 +0200
@@ -3,6 +3,7 @@
 	Written/copyright 1999-2001 by Donald Becker.
 	Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
 	Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com)
+	Portions copyright 2004 Harald Welte <laforge@gnumonks.org>
 
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
@@ -183,8 +184,6 @@
 				 NETIF_MSG_TX_ERR)
 static int debug = -1;
 
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
 static int mtu;
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
@@ -251,14 +250,11 @@
 MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(max_interrupt_work, 
-	"DP8381x maximum events handled per interrupt");
 MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
 MODULE_PARM_DESC(debug, "DP8381x default debug level");
 MODULE_PARM_DESC(rx_copybreak, 
@@ -769,6 +765,20 @@
 static int netdev_get_regs(struct net_device *dev, u8 *buf);
 static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
 
+static inline void natsemi_irq_enable(struct netdev_private *np)
+{
+	/* Enable interrupts by setting the interrupt mask. */
+	writel(DEFAULT_INTR, np->base_addr + IntrMask);
+	writel(1, np->base_addr + IntrEnable);
+	mb();
+}
+
+static inline void natsemi_irq_disable(struct netdev_private *np)
+{
+	writel(0, np->base_addr + IntrEnable);
+	mb();
+}
+
 static void move_int_phy(struct net_device *dev, int addr)
 {
 	struct netdev_private *np = netdev_priv(dev);
@@ -923,6 +933,11 @@
 	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NATSEMI_NAPI
+	dev->poll = natsemi_clean;
+	dev->weight = 64;
+#endif
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &natsemi_poll_controller;
 #endif
@@ -2135,6 +2150,62 @@
 	}
 }
 
+/* the second half of the interrupt handler, used for NAPI and non-NAPI path */
+#ifdef CONFIG_NATSEMI_NAPI
+static int intr_handler2(struct net_device *dev, int *work_done, int work_to_do)
+#else
+static int intr_handler2(struct net_device *dev)
+#endif
+{
+	struct netdev_private *np = netdev_priv(dev);
+	long ioaddr = dev->base_addr;
+	int boguscnt = max_interrupt_work;
+
+	/* Reading automatically acknowledges all int sources. */
+	u32 intr_status = readl(ioaddr + IntrStatus);
+
+	if (np->hands_off)
+		return 0;
+
+	if (intr_status == 0)
+		return 0;
+
+	if (netif_msg_intr(np))
+		printk(KERN_DEBUG
+			"%s: Interrupt, status %#08x, mask %#08x.\n",
+			dev->name, intr_status,
+			readl(ioaddr + IntrMask));
+
+	/* Abnormal error summary/uncommon events handlers. */
+	if (intr_status & IntrAbnormalSummary)
+		netdev_error(dev, intr_status);
+
+	if (intr_status &
+	   (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
+		spin_lock(&np->lock);
+		netdev_tx_done(dev);
+		spin_unlock(&np->lock);
+	}
+
+	if (intr_status &
+	   (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+	    IntrRxErr | IntrRxOverrun)) {
+#ifdef CONFIG_NATSEMI_NAPI
+		netdev_rx(dev, work_done, work_to_do);
+#else
+		netdev_rx(dev);
+#endif
+	}
+	/* FIXME: if quota not yet fulfilled, read status and restart
+	 * from top if non-null */
+
+	if (netif_msg_intr(np))
+		printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
+
+	return 1;
+}
+
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
@@ -2143,60 +2214,55 @@
 	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int boguscnt = max_interrupt_work;
-	unsigned int handled = 0;
 
-	if (np->hands_off)
+#ifdef CONFIG_NATSEMI_NAPI
+	if (n->hands_off) 
 		return IRQ_NONE;
-	do {
-		/* Reading automatically acknowledges all int sources. */
-		u32 intr_status = readl(ioaddr + IntrStatus);
-
-		if (netif_msg_intr(np))
-			printk(KERN_DEBUG
-				"%s: Interrupt, status %#08x, mask %#08x.\n",
-				dev->name, intr_status,
-				readl(ioaddr + IntrMask));
-
-		if (intr_status == 0)
-			break;
-		handled = 1;
 
-		if (intr_status &
-		   (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
-		    IntrRxErr | IntrRxOverrun)) {
-			netdev_rx(dev);
-		}
+	/* We cannot read IntrStatus since this would acknowledge
+	 * all interrupt sources. Thus we just blindly assume that
+	 * the interrupt really was for us -HW! */
+
+	if (netif_schedule_prep(dev)) {
+		/* Disable interrupts and register for poll */
+		natsemi_irq_disable(np);
+		__netif_rx_schedule(dev);
+	}
+	/* FIXME: IRQ_NONE since we're not sure whether it was for us ?  */ 
+	return IRQ_HANDLED;
+#else
+	return IRQ_RETVAL(intr_handler2(dev));
+#endif
+}
 
-		if (intr_status &
-		   (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
-			spin_lock(&np->lock);
-			netdev_tx_done(dev);
-			spin_unlock(&np->lock);
-		}
+#ifdef CONFIG_NATSEMI_NAPI
+static int natsemi_clean(struct net_device *dev, int *budget)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	int work_to_do = min(*budget, dev->quota);
+	int work_done = 0;
+	
+	intr_handler2(dev, &work_done, work_to_do);
 
-		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & IntrAbnormalSummary)
-			netdev_error(dev, intr_status);
-
-		if (--boguscnt < 0) {
-			if (netif_msg_intr(np))
-				printk(KERN_WARNING
-					"%s: Too much work at interrupt, "
-					"status=%#08x.\n",
-					dev->name, intr_status);
-			break;
-		}
-	} while (1);
+	*budget -= work_done;
+	dev->quota -= work_done;
 
-	if (netif_msg_intr(np))
-		printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
+	if (work_done < work_to_do || !netif_running(dev)) {
+		netif_rx_complete(dev);
+		natsemi_irq_enable(np);
+	}
 
-	return IRQ_RETVAL(handled);
+	return (work_done >= work_to_do);
 }
+#endif
 
 /* This routine is logically part of the interrupt handler, but separated
    for clarity and better register allocation. */
+#ifdef CONFIG_NATSEMI_NAPI
+static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
+#else
 static void netdev_rx(struct net_device *dev)
+#endif
 {
 	struct netdev_private *np = netdev_priv(dev);
 	int entry = np->cur_rx % RX_RING_SIZE;
@@ -2213,6 +2279,14 @@
 				entry, desc_status);
 		if (--boguscnt < 0)
 			break;
+
+#ifdef CONFIG_NATSEMI_NAPI
+		if (*work_done >= work_to_do)
+			break;
+
+		(*work_done)++;
+#endif
+
 		pkt_len = (desc_status & DescSizeMask) - 4;
 		if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
 			if (desc_status & DescMore) {
@@ -2269,7 +2343,11 @@
 				np->rx_skbuff[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_NATSEMI_NAPI
+			netif_receive_skb(skb);
+#else
 			netif_rx(skb);
+#endif
 			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
 			np->stats.rx_bytes += pkt_len;
