diff -uNrp linux-2.6.18.i686.orig/arch/i386/kernel/traps.c linux-2.6.18.i686/arch/i386/kernel/traps.c
--- linux-2.6.18.i686.orig/arch/i386/kernel/traps.c	2009-07-13 14:37:22.074900000 -0700
+++ linux-2.6.18.i686/arch/i386/kernel/traps.c	2009-07-13 14:58:01.047709000 -0700
@@ -394,6 +394,7 @@ void die(const char * str, struct pt_reg
 	};
 	static int die_counter;
 	unsigned long flags;
+	extern int crash_mode;
 
 	oops_enter();
 
@@ -438,6 +439,8 @@ void die(const char * str, struct pt_reg
 		if (notify_die(DIE_OOPS, str, regs, err,
 					current->thread.trap_no, SIGSEGV) !=
 				NOTIFY_STOP) {
+			if (kexec_should_crash(current))
+                                crash_mode = 1;
 			show_registers(regs);
 			/* Executive summary in case the oops scrolled away */
 			esp = (unsigned long) (&regs->esp);
diff -uNrp linux-2.6.18.i686.orig/arch/x86_64/kernel/traps.c linux-2.6.18.i686/arch/x86_64/kernel/traps.c
--- linux-2.6.18.i686.orig/arch/x86_64/kernel/traps.c	2009-07-13 14:37:47.346825000 -0700
+++ linux-2.6.18.i686/arch/x86_64/kernel/traps.c	2009-07-13 14:58:01.090702000 -0700
@@ -29,6 +29,7 @@
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
 #include <linux/unwind.h>
+#include <linux/netpoll.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -541,6 +542,7 @@ void __kprobes oops_end(unsigned long fl
 void __kprobes __die(const char * str, struct pt_regs * regs, long err)
 {
 	static int die_counter;
+	extern int crash_mode;
 	printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
 #ifdef CONFIG_PREEMPT
 	printk("PREEMPT ");
@@ -556,6 +558,8 @@ void __kprobes __die(const char * str, s
 	printk(KERN_ALERT "last sysfs file: %s\n", last_sysfs_file);
 #endif
 	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
+	if (kexec_should_crash(current))
+		crash_mode = 1;
 	show_registers(regs);
 	/* Executive summary in case the oops scrolled away */
 	printk(KERN_ALERT "RIP ");
diff -uNrp linux-2.6.18.i686.orig/drivers/char/sysrq.c linux-2.6.18.i686/drivers/char/sysrq.c
--- linux-2.6.18.i686.orig/drivers/char/sysrq.c	2009-07-13 14:37:56.237439000 -0700
+++ linux-2.6.18.i686/drivers/char/sysrq.c	2009-07-13 14:58:01.199668000 -0700
@@ -401,7 +401,8 @@ void __handle_sysrq(int key, struct pt_r
 	int i;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sysrq_key_table_lock, flags);
+	if (!spin_trylock(&sysrq_key_table_lock))
+		return;
 	orig_log_level = console_loglevel;
 	console_loglevel = 7;
 	printk(KERN_INFO "SysRq : ");
@@ -414,6 +415,11 @@ void __handle_sysrq(int key, struct pt_r
 		 */
 		if (!check_mask || sysrq_enabled == 1 ||
 		    (sysrq_enabled & op_p->enable_mask)) {
+			if (op_p == &sysrq_crashdump_op ||
+			    op_p == &sysrq_reboot_op) {
+				extern int crash_mode;
+				crash_mode = 1;
+			}
 			printk("%s\n", op_p->action_msg);
 			console_loglevel = orig_log_level;
 			op_p->handler(key, pt_regs, tty);
@@ -438,7 +444,7 @@ void __handle_sysrq(int key, struct pt_r
 		printk("\n");
 		console_loglevel = orig_log_level;
 	}
-	spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+	spin_unlock(&sysrq_key_table_lock);
 }
 
 /*
diff -uNrp linux-2.6.18.i686.orig/drivers/net/bonding/bonding.h linux-2.6.18.i686/drivers/net/bonding/bonding.h
--- linux-2.6.18.i686.orig/drivers/net/bonding/bonding.h	2009-07-13 14:38:13.245712000 -0700
+++ linux-2.6.18.i686/drivers/net/bonding/bonding.h	2009-07-13 14:58:01.231672000 -0700
@@ -18,6 +18,9 @@
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
 #include <linux/if_bonding.h>
+#ifdef CONFIG_NET_POLL_CONTROLLER
+#include <linux/netpoll.h>
+#endif
 #include <linux/kobject.h>
 #include <linux/in6.h>
 #include "bond_3ad.h"
@@ -198,10 +201,17 @@ struct slave {
  */
 struct bonding {
 	struct   net_device *dev; /* first - useful for panic debug */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	void (*netpoll_setup)(struct net_device *dev, struct netpoll_info *npinfo);
+	int (*netpoll_xmit_setup)(struct netpoll *np, struct sk_buff **skbp);
+	void (*netpoll_cleanup)(struct net_device *dev);
+	struct   slave *curr_np_slave;
+#endif
 	struct   slave *first_slave;
 	struct   slave *curr_active_slave;
 	struct   slave *current_arp_slave;
 	struct   slave *primary_slave;
+
 	s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
 	rwlock_t lock;
 	rwlock_t curr_slave_lock;
diff -uNrp linux-2.6.18.i686.orig/drivers/net/bonding/bond_main.c linux-2.6.18.i686/drivers/net/bonding/bond_main.c
--- linux-2.6.18.i686.orig/drivers/net/bonding/bond_main.c	2009-07-13 14:38:13.237710000 -0700
+++ linux-2.6.18.i686/drivers/net/bonding/bond_main.c	2009-07-13 14:58:01.262665000 -0700
@@ -414,6 +414,7 @@ int bond_dev_queue_xmit(struct bonding *
 	}
 
 	skb->priority = 1;
+
 	dev_queue_xmit(skb);
 
 	return 0;
@@ -1336,6 +1337,54 @@ static void bond_detach_slave(struct bon
 	bond->slave_cnt--;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static int slaves_support_netpoll(struct net_device *bond_dev)
+{
+	struct bonding *bond = bond_dev->priv;
+	struct slave *slave;
+	int i;
+
+	bond_for_each_slave(bond, slave, i) {
+		if (!slave->dev->poll_controller)
+			return 0;
+	}
+
+	return 1;
+}
+
+static void bond_poll_controller(struct net_device *bond_dev)
+{
+	struct bonding *bond = bond_dev->priv;
+	struct slave *slave;
+
+	if ((slave = bond->curr_np_slave) &&
+	     slave->dev->poll_controller)
+		netpoll_poll_dev(slave->dev);
+}
+
+static void bond_netpoll_setup(struct net_device *bond_dev,
+                              struct netpoll_info *npinfo)
+{
+	struct bonding *bond = bond_dev->priv;
+	struct slave *slave;
+	int i;
+
+	bond_for_each_slave(bond, slave, i) {
+		slave->dev->npinfo = npinfo;
+	}
+}
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+	struct bonding *bond = bond_dev->priv;
+	struct slave *slave;
+	int i;
+
+	bond_for_each_slave(bond, slave, i) {
+		dev_put(slave->dev);
+	}
+}
+#endif
+
 /*---------------------------------- IOCTL ----------------------------------*/
 
 static int bond_sethwaddr(struct net_device *bond_dev,
@@ -1778,6 +1827,18 @@ int bond_enslave(struct net_device *bond
 	       new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup",
 	       new_slave->link != BOND_LINK_DOWN ? "n up" : " down");
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	if (slaves_support_netpoll(bond_dev)) {
+		bond_dev->poll_controller = bond_poll_controller;
+		slave_dev->npinfo = bond_dev->npinfo;
+	} else if (bond_dev->poll_controller) {
+		bond_dev->poll_controller = NULL;
+		printk("New slave device %s does not support netpoll.\n",
+			slave_dev->name);
+		printk("netpoll disabled for %s.\n", bond_dev->name);
+	}
+#endif
+
 	/* enslave is successful */
 	return 0;
 
@@ -1828,7 +1889,7 @@ int bond_release(struct net_device *bond
 
 	/* slave is not a slave or master is not master of this slave */
 	if (!(slave_dev->flags & IFF_SLAVE) ||
-	    (slave_dev->master != bond_dev)) {
+	    (slave_dev->master != bond_dev)) { 
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Error: cannot release %s.\n",
 		       bond_dev->name, slave_dev->name);
@@ -4503,6 +4564,68 @@ out:
 	return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+int bond_xmit_netpoll(struct netpoll *np, struct sk_buff **skbp)
+{
+	struct net_device *bond_dev = np->dev;
+	struct bonding *bond = bond_dev->priv;
+	struct slave *slave, *start_at;
+	int ab = (bond_dev->hard_start_xmit == bond_xmit_activebackup);
+	int i, ret = 0;
+	struct sk_buff *skb = *skbp;
+
+	while (!read_trylock(&bond->lock)) {
+		if (in_interrupt())
+			goto rel;
+	}
+	while (!read_trylock(&bond->curr_slave_lock)) {
+		if (in_interrupt())
+			goto out2;
+	}
+
+	if (!BOND_IS_OK(bond))
+		goto out;
+	if (!bond->curr_np_slave || ab)
+		bond->curr_np_slave = bond->curr_active_slave;
+	if (!bond->curr_np_slave && !ab)
+		bond->curr_np_slave = bond->first_slave;
+	if (!(start_at = bond->curr_np_slave))
+		goto out;
+	bond_for_each_slave_from(bond, slave, i, start_at) {
+		if (IS_UP(slave->dev) &&
+		   (slave->link == BOND_LINK_UP) &&
+		    (slave->state == BOND_STATE_ACTIVE)) {
+			unsigned short vlan_id;
+
+			if (!list_empty(&bond->vlan_list) &&
+	    		    !(slave->dev->features & NETIF_F_HW_VLAN_TX) &&
+		    	    vlan_get_tag(skb, &vlan_id) == 0) {
+				skb->dev = slave->dev;
+				skb = vlan_put_tag(skb, vlan_id);
+				if (!skb) {
+					break;
+				}
+			} else {
+				skb->dev = slave->dev;
+			}
+			skb->priority = 1;
+			dev_hold(skb->dev);
+			ret = 1;
+			break;
+		}
+	}
+out:
+	read_unlock(&bond->curr_slave_lock);
+out2:
+	read_unlock(&bond->lock);
+rel:
+	if (!ret && skb)
+		__kfree_skb(skb);
+	*skbp = skb;
+	return ret;
+}
+#endif
+
 /*------------------------- Device initialization ---------------------------*/
 
 static void bond_set_xmit_hash_policy(struct bonding *bond)
@@ -4626,6 +4749,16 @@ static int bond_init(struct net_device *
 
 	bond_dev->destructor = bond_destructor;
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	{
+		struct bonding *bond = bond_dev->priv;
+		bond->netpoll_setup = bond_netpoll_setup;
+		bond->netpoll_xmit_setup = bond_xmit_netpoll;
+		bond->netpoll_cleanup = bond_netpoll_cleanup;
+		bond->curr_np_slave = 0;
+	}
+#endif
+
 	/* Initialize the device options */
 	bond_dev->tx_queue_len = 0;
 	bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
diff -uNrp linux-2.6.18.i686.orig/drivers/net/e1000/e1000_main.c linux-2.6.18.i686/drivers/net/e1000/e1000_main.c
--- linux-2.6.18.i686.orig/drivers/net/e1000/e1000_main.c	2009-07-13 14:38:13.936709000 -0700
+++ linux-2.6.18.i686/drivers/net/e1000/e1000_main.c	2009-07-13 14:58:01.334666000 -0700
@@ -4090,27 +4090,29 @@ e1000_clean_tx_irq(struct e1000_adapter 
 		         E1000_STATUS_TXOFF)) {
 
 			/* detected Tx unit hang */
-			DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
-					"  Tx Queue             <%lu>\n"
-					"  TDH                  <%x>\n"
-					"  TDT                  <%x>\n"
-					"  next_to_use          <%x>\n"
-					"  next_to_clean        <%x>\n"
-					"buffer_info[next_to_clean]\n"
-					"  time_stamp           <%lx>\n"
-					"  next_to_watch        <%x>\n"
-					"  jiffies              <%lx>\n"
-					"  next_to_watch.status <%x>\n",
-				(unsigned long)((tx_ring - adapter->tx_ring) /
-					sizeof(struct e1000_tx_ring)),
-				readl(adapter->hw.hw_addr + tx_ring->tdh),
-				readl(adapter->hw.hw_addr + tx_ring->tdt),
-				tx_ring->next_to_use,
-				tx_ring->next_to_clean,
-				tx_ring->buffer_info[eop].time_stamp,
-				eop,
-				jiffies,
-				eop_desc->upper.fields.status);
+			if (!in_interrupt()) {
+				DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
+						"  Tx Queue             <%lu>\n"
+						"  TDH                  <%x>\n"
+						"  TDT                  <%x>\n"
+						"  next_to_use          <%x>\n"
+						"  next_to_clean        <%x>\n"
+						"buffer_info[next_to_clean]\n"
+						"  time_stamp           <%lx>\n"
+						"  next_to_watch        <%x>\n"
+						"  jiffies              <%lx>\n"
+						"  next_to_watch.status <%x>\n",
+					(unsigned long)((tx_ring - adapter->tx_ring) /
+						sizeof(struct e1000_tx_ring)),
+					readl(adapter->hw.hw_addr + tx_ring->tdh),
+					readl(adapter->hw.hw_addr + tx_ring->tdt),
+					tx_ring->next_to_use,
+					tx_ring->next_to_clean,
+					tx_ring->buffer_info[eop].time_stamp,
+					eop,
+					jiffies,
+					eop_desc->upper.fields.status);
+			}
 			netif_stop_queue(netdev);
 		}
 	}
diff -uNrp linux-2.6.18.i686.orig/drivers/net/e1000/e1000_param.c linux-2.6.18.i686/drivers/net/e1000/e1000_param.c
--- linux-2.6.18.i686.orig/drivers/net/e1000/e1000_param.c	2009-07-13 14:38:13.943720000 -0700
+++ linux-2.6.18.i686/drivers/net/e1000/e1000_param.c	2009-07-13 14:58:01.298666000 -0700
@@ -530,7 +530,7 @@ e1000_check_options(struct e1000_adapter
 			}
 		} else {
 			adapter->itr_setting = opt.def;
-			adapter->itr = 20000;
+			adapter->itr = 6000;
 		}
 	}
 	{ /* Smart Power Down */
diff -uNrp linux-2.6.18.i686.orig/drivers/xen/netfront/netfront.c linux-2.6.18.i686/drivers/xen/netfront/netfront.c
--- linux-2.6.18.i686.orig/drivers/xen/netfront/netfront.c	2009-07-13 14:38:43.452417000 -0700
+++ linux-2.6.18.i686/drivers/xen/netfront/netfront.c	2009-07-13 14:58:01.505665000 -0700
@@ -928,6 +928,7 @@ static int network_start_xmit(struct sk_
 	int frags = skb_shinfo(skb)->nr_frags;
 	unsigned int offset = offset_in_page(data);
 	unsigned int len = skb_headlen(skb);
+	unsigned long flags;
 
 	frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
 	if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
@@ -937,12 +938,12 @@ static int network_start_xmit(struct sk_
 		goto drop;
 	}
 
-	spin_lock_irq(&np->tx_lock);
+	spin_lock_irqsave(&np->tx_lock, flags);
 
 	if (unlikely(!netif_carrier_ok(dev) ||
 		     (frags > 1 && !xennet_can_sg(dev)) ||
 		     netif_needs_gso(dev, skb))) {
-		spin_unlock_irq(&np->tx_lock);
+		spin_unlock_irqrestore(&np->tx_lock, flags);
 		goto drop;
 	}
 
@@ -1012,7 +1013,7 @@ static int network_start_xmit(struct sk_
 	if (!netfront_tx_slot_available(np))
 		netif_stop_queue(dev);
 
-	spin_unlock_irq(&np->tx_lock);
+	spin_unlock_irqrestore(&np->tx_lock, flags);
 
 	return 0;
 
@@ -1022,6 +1023,14 @@ static int network_start_xmit(struct sk_
 	return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void netif_poll_controller(struct net_device *dev)
+{
+
+	netif_int(NULL, dev, NULL);
+}
+#endif
+
 static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	struct net_device *dev = dev_id;
@@ -2021,6 +2030,10 @@ static struct net_device * __devinit cre
 	netdev->weight          = 64;
 	netdev->features        = NETIF_F_IP_CSUM;
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = netif_poll_controller;
+#endif
+
 	SET_ETHTOOL_OPS(netdev, &network_ethtool_ops);
 	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &dev->dev);
diff -uNrp linux-2.6.18.i686.orig/include/linux/netpoll.h linux-2.6.18.i686/include/linux/netpoll.h
--- linux-2.6.18.i686.orig/include/linux/netpoll.h	2009-07-13 14:39:25.257612000 -0700
+++ linux-2.6.18.i686/include/linux/netpoll.h	2009-07-13 14:58:01.548666000 -0700
@@ -43,6 +43,10 @@ void netpoll_set_trap(int trap);
 void netpoll_cleanup(struct netpoll *np);
 int __netpoll_rx(struct sk_buff *skb);
 void netpoll_queue(struct sk_buff *skb);
+int netpoll_setup_v2(struct netpoll *np);
+void netpoll_cleanup_v2(struct netpoll *np);
+int netpoll_send_msg(struct netpoll *np, const char *msg, int len);
+void netpoll_poll_dev(struct net_device *dev);
 
 #ifdef CONFIG_NETPOLL
 static inline int netpoll_rx(struct sk_buff *skb)
diff -uNrp linux-2.6.18.i686.orig/kernel/panic.c linux-2.6.18.i686/kernel/panic.c
--- linux-2.6.18.i686.orig/kernel/panic.c	2009-07-13 14:39:32.726312000 -0700
+++ linux-2.6.18.i686/kernel/panic.c	2009-07-13 14:58:01.589703000 -0700
@@ -19,12 +19,15 @@
 #include <linux/nmi.h>
 #include <linux/kexec.h>
 #include <linux/debug_locks.h>
+#include <linux/netpoll.h>
 
 int panic_on_oops = 1;
 int tainted;
 static int pause_on_oops;
 static int pause_on_oops_flag;
 static DEFINE_SPINLOCK(pause_on_oops_lock);
+int crash_mode = 0;
+EXPORT_SYMBOL(crash_mode);
 
 int panic_timeout;
 
@@ -65,6 +68,7 @@ NORET_TYPE void panic(const char * fmt, 
 #if defined(CONFIG_S390)
         unsigned long caller = (unsigned long) __builtin_return_address(0);
 #endif
+	crash_mode = 1;
 
 	/*
 	 * It's possible to come here directly from a panic-assertion and not
diff -uNrp linux-2.6.18.i686.orig/kernel/printk.c linux-2.6.18.i686/kernel/printk.c
--- linux-2.6.18.i686.orig/kernel/printk.c	2009-07-13 14:39:32.923310000 -0700
+++ linux-2.6.18.i686/kernel/printk.c	2009-07-13 14:58:01.628666000 -0700
@@ -693,6 +693,8 @@ out_restore_irqs:
 		local_irq_restore(flags);
 	}
 
+	if (unlikely(!in_interrupt() && !irqs_disabled() && local_softirq_pending()))
+		do_softirq();
 	preempt_enable();
 	return printed_len;
 }
--- linux-2.6.18.i686/drivers/net/netconsole.c.orig	2006-09-19 20:42:06.000000000 -0700
+++ linux-2.6.18.i686/drivers/net/netconsole.c	2009-07-16 16:20:01.421812000 -0700
@@ -60,30 +60,66 @@ static struct netpoll np = {
 	.local_port = 6665,
 	.remote_port = 6666,
 	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-	.drop = netpoll_queue,
 };
 static int configured = 0;
 
-#define MAX_PRINT_CHUNK 1000
+static struct timer_list nc_timer;
+static DEFINE_SPINLOCK(nc_lock);
+static int nc_lock_owner = -1;
+
+#define MAX_PRINT_CHUNK 980
+#define SYSLOG_HEADER_LEN 0
+
+static int syslog_chars = SYSLOG_HEADER_LEN;
+static unsigned char syslog_line [MAX_PRINT_CHUNK + 10];
+extern int crash_mode;
+
+static inline void feed_syslog_char(const unsigned char c)
+{
+        syslog_line[syslog_chars] = c;
+        syslog_chars++;
+        if (syslog_chars == MAX_PRINT_CHUNK || 
+	    (crash_mode && c == '\n')) {
+                netpoll_send_msg(&np, syslog_line, syslog_chars);
+                syslog_chars = SYSLOG_HEADER_LEN;
+        }
+}
 
 static void write_msg(struct console *con, const char *msg, unsigned int len)
 {
-	int frag, left;
+	int i;
 	unsigned long flags;
 
 	if (!np.dev)
 		return;
 
-	local_irq_save(flags);
-
-	for(left = len; left; ) {
-		frag = min(left, MAX_PRINT_CHUNK);
-		netpoll_send_udp(&np, msg, frag);
-		msg += frag;
-		left -= frag;
+	while (!spin_trylock_irqsave(&nc_lock, flags)) {
+		if (nc_lock_owner == smp_processor_id())
+			return;
 	}
+	nc_lock_owner = smp_processor_id();
+
+	for (i = 0; i < len; i++)
+       		feed_syslog_char(msg[i]);
 
-	local_irq_restore(flags);
+	nc_lock_owner = -1;
+	spin_unlock_irqrestore(&nc_lock, flags);
+}
+
+static int last_chars = 0;
+static void flush_timer(unsigned long p)
+{
+	if (spin_trylock(&nc_lock)) {
+		nc_lock_owner = smp_processor_id();
+		if (syslog_chars > 0 && syslog_chars == last_chars) {
+                	if (netpoll_send_msg(&np, syslog_line, syslog_chars))
+                		syslog_chars = SYSLOG_HEADER_LEN;
+		}
+		nc_lock_owner = -1;
+		spin_unlock(&nc_lock);
+	}
+	last_chars = syslog_chars;
+	mod_timer(&nc_timer, jiffies + HZ/10);
 }
 
 static struct console netconsole = {
@@ -107,21 +143,32 @@ static int init_netconsole(void)
 
 	if(!configured) {
 		printk("netconsole: not configured, aborting\n");
-		return 0;
+		return -EINVAL;
 	}
 
-	if(netpoll_setup(&np))
+	if(netpoll_setup_v2(&np))
 		return -EINVAL;
 
 	register_console(&netconsole);
+	init_timer(&nc_timer);
+	nc_timer.function = flush_timer;
+	nc_timer.data = (unsigned long)0;
+	mod_timer(&nc_timer, jiffies + HZ/10);
 	printk(KERN_INFO "netconsole: network logging started\n");
 	return 0;
 }
 
 static void cleanup_netconsole(void)
 {
+	int flags;
+
+	del_timer_sync(&nc_timer);
+	spin_lock_irqsave(&nc_lock, flags);
+	nc_lock_owner = smp_processor_id();
 	unregister_console(&netconsole);
-	netpoll_cleanup(&np);
+	netpoll_cleanup_v2(&np);
+	nc_lock_owner = -1;
+	spin_unlock_irqrestore(&nc_lock, flags);
 }
 
 module_init(init_netconsole);
--- linux-2.6.18.i686/net/core/netpoll.c.orig	2009-08-07 11:29:17.000000000 -0700
+++ linux-2.6.18.i686/net/core/netpoll.c	2009-08-07 11:34:34.000000000 -0700
@@ -190,13 +190,20 @@ static void service_arp_queue(struct net
 
 void netpoll_poll(struct netpoll *np)
 {
+	struct netpoll_info *npinfo;
+
 	if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
 		return;
 
-	/* Process pending work on NIC */
+	npinfo = np->dev->npinfo;
 	np->dev->poll_controller(np->dev);
+
+        if (np->dev->flags & IFF_MASTER)
+		return;
+
+	/* Process pending work on NIC */
 	if (np->dev->poll)
-		poll_napi(np);
+		poll_napi(np->dev);
 
 	service_arp_queue(np->dev->npinfo);
 
@@ -828,3 +835,368 @@ EXPORT_SYMBOL(netpoll_cleanup);
 EXPORT_SYMBOL(netpoll_send_udp);
 EXPORT_SYMBOL(netpoll_poll);
 EXPORT_SYMBOL(netpoll_queue);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+/* netconsole support
+ */
+#define MAX_NC_RETRIES	1000
+extern int crash_mode;
+
+struct netpoll_info_ext {
+	struct   net_device *dev;
+	void (*netpoll_setup)(struct net_device *dev, struct netpoll_info *npinfo);
+	int (*netpoll_xmit_setup)(struct netpoll *np, struct sk_buff **skbp);
+	void (*netpoll_cleanup)(struct net_device *dev);
+};
+
+static inline int netpoll_set_dev(struct netpoll *np, struct sk_buff **skbp)
+{
+	struct sk_buff *skb = *skbp;
+
+	skb->dev = np->dev;
+        if (np->dev->flags & IFF_MASTER) {
+		struct netpoll_info_ext *npx = (struct netpoll_info_ext *)np->dev->priv;
+		/* Note: If failed, skb is freed already
+		 */
+		return (npx->netpoll_xmit_setup(np, skbp));
+	}
+	return 1;
+}
+
+void netpoll_poll_dev(struct net_device *dev)
+{
+	int flags;
+	struct netpoll_info *npinfo;
+
+        if(!netif_running(dev) || !dev->poll_controller)
+                return;
+
+        /* Process pending work on NIC */
+	npinfo = dev->npinfo;
+	if (spin_trylock_irqsave(&npinfo->poll_lock, flags)) {
+		dev->poll_controller(dev);
+		spin_unlock_irqrestore(&npinfo->poll_lock, flags);
+	}
+        if (dev->poll)
+                poll_napi(dev);
+
+	service_arp_queue(dev->npinfo);
+
+	zap_completion_queue();
+}
+
+static struct sk_buff * find_msg_skb(struct netpoll *np, int len, int reserve)
+{
+	int once = 1, count = 0;
+	struct sk_buff *skb = NULL;
+
+	zap_completion_queue();
+repeat:
+	skb = alloc_skb(len, GFP_ATOMIC);
+
+	if(!skb) {
+		count++;
+		if (once && (count == 1000000)) {
+			printk("out of netpoll skbs!\n");
+			once = 0;
+		}
+		if ((count & 0xf) == 0)
+			netpoll_poll(np);
+		if (in_interrupt())
+		 	return 0;
+		udelay(100);
+		goto repeat;
+	}
+
+	atomic_set(&skb->users, 1);
+	skb_reserve(skb, reserve);
+	return skb;
+}
+
+static int netpoll_send_msg_skb(struct netpoll *np, struct sk_buff *skb)
+{
+	int status;
+	struct net_device *dev = skb->dev;
+	struct netpoll_info *npinfo;
+	int flags;
+
+	if (!np || !dev || !netif_running(dev)) {
+		__kfree_skb(skb);
+		return 1;
+	}
+
+	npinfo = dev->npinfo;
+
+	/* avoid recursion */
+	if (npinfo->poll_owner == smp_processor_id() ||
+	    dev->xmit_lock_owner == smp_processor_id()) {
+		if (np->drop)
+			np->drop(skb);
+		else
+			__kfree_skb(skb);
+		return 1;
+	}
+
+	do {
+		npinfo->tries--;
+		status = NETDEV_TX_BUSY;
+
+		local_irq_save(flags);
+		if (netif_tx_trylock(dev)) {
+			/*
+			 * network drivers do not expect to be called if the queue is
+			 * stopped.
+			 */
+			if (!netif_queue_stopped(dev))
+				status = dev->hard_start_xmit(skb, dev);
+			netif_tx_unlock(dev);
+		}
+		local_irq_restore(flags);
+
+		/* success */
+		if(!status) {
+			npinfo->tries = MAX_NC_RETRIES; /* reset */
+			return 1;
+		}
+
+		/* transmit busy */
+		if ((npinfo->tries & 0x1) == 0)
+			netpoll_poll_dev(dev);
+		if (in_interrupt())
+			break;
+		udelay(1000);
+	} while (npinfo->tries > 0);
+	__kfree_skb(skb);
+	return 0;
+}
+
+int netpoll_send_msg(struct netpoll *np, const char *msg, int len)
+{
+	int total_len, eth_len, ip_len, udp_len;
+	struct sk_buff *skb;
+	struct udphdr *udph;
+	struct iphdr *iph;
+	struct ethhdr *eth;
+	int ret;
+
+	udp_len = len + sizeof(*udph);
+	ip_len = eth_len = udp_len + sizeof(*iph);
+	total_len = eth_len + ETH_HLEN + NET_IP_ALIGN;
+
+	skb = find_msg_skb(np, total_len, total_len - len);
+	if (!skb)
+		return 0;
+
+	{
+		const char *s = msg;
+		char *d = skb->data;
+		int i;
+		for (i = 0; i < len; i++)
+			*d++ = *s++;
+	}
+	skb->len += len;
+
+	udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+	skb->h.uh = udph;
+	udph->source = htons(np->local_port);
+	udph->dest = htons(np->remote_port);
+	udph->len = htons(udp_len);
+	udph->check = 0;
+	udph->check = csum_tcpudp_magic(htonl(np->local_ip),
+					htonl(np->remote_ip),
+					udp_len, IPPROTO_UDP,
+					csum_partial((unsigned char *)udph, udp_len, 0));
+	if (udph->check == 0)
+		udph->check = -1;
+
+	iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+	skb->nh.iph = iph;
+
+	/* iph->version = 4; iph->ihl = 5; */
+	put_unaligned(0x45, (unsigned char *)iph);
+	iph->tos      = 0;
+	put_unaligned(htons(ip_len), &(iph->tot_len));
+	iph->id       = 0;
+	iph->frag_off = 0;
+	iph->ttl      = 64;
+	iph->protocol = IPPROTO_UDP;
+	iph->check    = 0;
+	put_unaligned(htonl(np->local_ip), &(iph->saddr));
+	put_unaligned(htonl(np->remote_ip), &(iph->daddr));
+	iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	eth->h_proto = htons(ETH_P_IP);
+	memcpy(eth->h_source, np->local_mac, 6);
+	memcpy(eth->h_dest, np->remote_mac, 6);
+
+	skb->dev = np->dev;
+	if (!(netpoll_set_dev(np, &skb)))
+		return 0;
+
+	ret = netpoll_send_msg_skb(np, skb);
+
+        if (np->dev->flags & IFF_MASTER)
+		dev_put(skb->dev);
+
+	return ret;
+	
+}
+
+int netpoll_setup_v2(struct netpoll *np)
+{
+	struct net_device *ndev = NULL;
+	struct in_device *in_dev;
+	struct netpoll_info *npinfo;
+	unsigned long flags;
+
+	if (np->dev_name)
+		ndev = dev_get_by_name(np->dev_name);
+	if (!ndev) {
+		printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
+		       np->name, np->dev_name);
+		return -1;
+	}
+
+	np->dev = ndev;
+	if (!ndev->npinfo) {
+		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
+		if (!npinfo)
+			goto release;
+
+		npinfo->rx_flags = 0;
+		npinfo->rx_np = NULL;
+		spin_lock_init(&npinfo->poll_lock);
+		npinfo->poll_owner = -1;
+		npinfo->tries = MAX_NC_RETRIES;
+		spin_lock_init(&npinfo->rx_lock);
+		skb_queue_head_init(&npinfo->arp_tx);
+	} else
+		npinfo = ndev->npinfo;
+
+	if (!ndev->poll_controller) {
+		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
+		       np->name, np->dev_name);
+		goto release;
+	}
+
+	if (!netif_running(ndev)) {
+		unsigned long atmost, atleast;
+
+		printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
+		       np->name, np->dev_name);
+
+		rtnl_lock();
+		if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) {
+			printk(KERN_ERR "%s: failed to open %s\n",
+			       np->name, np->dev_name);
+			rtnl_unlock();
+			goto release;
+		}
+		rtnl_unlock();
+
+		atleast = jiffies + HZ/10;
+ 		atmost = jiffies + 4*HZ;
+		while (!netif_carrier_ok(ndev)) {
+			if (time_after(jiffies, atmost)) {
+				printk(KERN_NOTICE
+				       "%s: timeout waiting for carrier\n",
+				       np->name);
+				break;
+			}
+			cond_resched();
+		}
+
+		/* If carrier appears to come up instantly, we don't
+		 * trust it and pause so that we don't pump all our
+		 * queued console messages into the bitbucket.
+		 */
+
+		if (time_before(jiffies, atleast)) {
+			printk(KERN_NOTICE "%s: carrier detect appears"
+			       " untrustworthy, waiting 4 seconds\n",
+			       np->name);
+			msleep(4000);
+		}
+	}
+
+	if (is_zero_ether_addr(np->local_mac) && ndev->dev_addr)
+		memcpy(np->local_mac, ndev->dev_addr, 6);
+
+	if (!np->local_ip) {
+		rcu_read_lock();
+		in_dev = __in_dev_get_rcu(ndev);
+
+		if (!in_dev || !in_dev->ifa_list) {
+			rcu_read_unlock();
+			printk(KERN_ERR "%s: no IP address for %s, aborting\n",
+			       np->name, np->dev_name);
+			goto release;
+		}
+
+		np->local_ip = ntohl(in_dev->ifa_list->ifa_local);
+		rcu_read_unlock();
+		printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->local_ip));
+	}
+
+	if (np->rx_hook) {
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		npinfo->rx_flags |= NETPOLL_RX_ENABLED;
+		npinfo->rx_np = np;
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+	}
+
+	/* last thing to do is link it to the net device structure */
+	ndev->npinfo = npinfo;
+
+	/* avoid racing with NAPI reading npinfo */
+	synchronize_rcu();
+
+        /* Call the device specific netpoll initialization routine. */
+        if (ndev->flags & IFF_MASTER) {
+		struct netpoll_info_ext *npx = (struct netpoll_info_ext *)ndev->priv;
+                npx->netpoll_setup(ndev, npinfo);
+	}
+
+	return 0;
+
+ release:
+	if (!ndev->npinfo)
+		kfree(npinfo);
+	np->dev = NULL;
+	dev_put(ndev);
+	return -1;
+}
+
+void netpoll_cleanup_v2(struct netpoll *np)
+{
+	struct netpoll_info *npinfo;
+	unsigned long flags;
+
+	if (np->dev) {
+		npinfo = np->dev->npinfo;
+		if (npinfo && npinfo->rx_np == np) {
+			spin_lock_irqsave(&npinfo->rx_lock, flags);
+			npinfo->rx_np = NULL;
+			npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+			spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+		}
+        	/* Call the device specific netpoll cleanup routine. */
+		if (np->dev->flags & IFF_MASTER) {
+			struct netpoll_info_ext *npx = (struct netpoll_info_ext *)np->dev->priv;
+			npx->netpoll_cleanup(np->dev);
+		}
+		dev_put(np->dev);
+	}
+
+	np->dev = NULL;
+}
+
+EXPORT_SYMBOL(netpoll_setup_v2);
+EXPORT_SYMBOL(netpoll_cleanup_v2);
+EXPORT_SYMBOL(netpoll_send_msg);
+EXPORT_SYMBOL(netpoll_poll_dev);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
