Xen 
 
Home About Xen.org Xen Xen Summit Wiki Mailing List Bug Tracker Xen Downloads
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [LINUX] Update to 2.6.16.33.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [LINUX] Update to 2.6.16.33.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 28 Nov 2006 20:00:15 +0000
Delivery-date: Tue, 28 Nov 2006 11:59:52 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
# Node ID 6c2c7ff6265a9c47bb851c89dde5aae4ed58de02
# Parent  7826e5482d421cf3bfd2a3e54800f7a21ca2a9f9
[LINUX] Update to 2.6.16.33.

No changes required to sparse tree or patches directory.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
---
 patches/linux-2.6.16.32/blktap-aio-16_03_06.patch                              
          |  271 -
 patches/linux-2.6.16.32/device_bind.patch                                      
          |   14 
 patches/linux-2.6.16.32/fix-hz-suspend.patch                                   
          |   25 
 patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch                              
          |   13 
 patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch                           
          |   35 
 patches/linux-2.6.16.32/ipv6-no-autoconf.patch                                 
          |   18 
 patches/linux-2.6.16.32/kasprintf.patch                                        
          |   57 
 patches/linux-2.6.16.32/net-csum.patch                                         
          |   57 
 patches/linux-2.6.16.32/net-gso-0-base.patch                                   
          | 2501 ----------
 patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch                            
          |   22 
 patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch                           
          |  400 -
 patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch                         
          |   13 
 patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch                            
          |   16 
 patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch                                
          |   11 
 patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch                     
          |  252 -
 patches/linux-2.6.16.32/pmd-shared.patch                                       
          |  100 
 patches/linux-2.6.16.32/rcu_needs_cpu.patch                                    
          |   33 
 patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch     
          |   26 
 patches/linux-2.6.16.32/series                                                 
          |   27 
 patches/linux-2.6.16.32/smp-alts.patch                                         
          |  540 --
 patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch                                
          | 1380 -----
 patches/linux-2.6.16.32/vsnprintf.patch                                        
          |  178 
 patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch                
          |   27 
 patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch              
          |   73 
 
patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
    |  138 
 
patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
 |   72 
 patches/linux-2.6.16.32/xen-hotplug.patch                                      
          |   10 
 patches/linux-2.6.16.32/xenoprof-generic.patch                                 
          |  615 --
 buildconfigs/mk.linux-2.6-xen                                                  
          |    2 
 patches/linux-2.6.16.33/blktap-aio-16_03_06.patch                              
          |  161 
 patches/linux-2.6.16.33/device_bind.patch                                      
          |    9 
 patches/linux-2.6.16.33/fix-hz-suspend.patch                                   
          |    9 
 patches/linux-2.6.16.33/fix-ide-cd-pio-mode.patch                              
          |   13 
 patches/linux-2.6.16.33/i386-mach-io-check-nmi.patch                           
          |   30 
 patches/linux-2.6.16.33/ipv6-no-autoconf.patch                                 
          |   16 
 patches/linux-2.6.16.33/kasprintf.patch                                        
          |   32 
 patches/linux-2.6.16.33/net-csum.patch                                         
          |   40 
 patches/linux-2.6.16.33/net-gso-0-base.patch                                   
          | 1970 +++++++
 patches/linux-2.6.16.33/net-gso-1-check-dodgy.patch                            
          |   16 
 patches/linux-2.6.16.33/net-gso-2-checksum-fix.patch                           
          |  311 +
 patches/linux-2.6.16.33/net-gso-3-fix-errorcheck.patch                         
          |   13 
 patches/linux-2.6.16.33/net-gso-4-kill-warnon.patch                            
          |   26 
 patches/linux-2.6.16.33/net-gso-5-rcv-mss.patch                                
          |   11 
 patches/linux-2.6.16.33/pci-mmconfig-fix-from-2.6.17.patch                     
          |  143 
 patches/linux-2.6.16.33/pmd-shared.patch                                       
          |   57 
 patches/linux-2.6.16.33/rcu_needs_cpu.patch                                    
          |   18 
 patches/linux-2.6.16.33/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch     
          |   26 
 patches/linux-2.6.16.33/series                                                 
          |   27 
 patches/linux-2.6.16.33/smp-alts.patch                                         
          |  330 +
 patches/linux-2.6.16.33/tpm_plugin_2.6.17.patch                                
          |  703 ++
 patches/linux-2.6.16.33/vsnprintf.patch                                        
          |  177 
 patches/linux-2.6.16.33/x86-elfnote-as-preprocessor-macro.patch                
          |   25 
 patches/linux-2.6.16.33/x86-increase-interrupt-vector-range.patch              
          |   73 
 
patches/linux-2.6.16.33/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
    |   39 
 
patches/linux-2.6.16.33/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
 |   63 
 patches/linux-2.6.16.33/xen-hotplug.patch                                      
          |   10 
 patches/linux-2.6.16.33/xenoprof-generic.patch                                 
          |  294 +
 57 files changed, 4643 insertions(+), 6925 deletions(-)

diff -r 7826e5482d42 -r 6c2c7ff6265a buildconfigs/mk.linux-2.6-xen
--- a/buildconfigs/mk.linux-2.6-xen     Tue Nov 28 14:27:13 2006 +0000
+++ b/buildconfigs/mk.linux-2.6-xen     Tue Nov 28 15:25:26 2006 +0000
@@ -1,5 +1,5 @@ LINUX_SERIES = 2.6
 LINUX_SERIES = 2.6
-LINUX_VER    = 2.6.16.32
+LINUX_VER    = 2.6.16.33
 
 EXTRAVERSION ?= xen
 
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/blktap-aio-16_03_06.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/blktap-aio-16_03_06.patch Tue Nov 28 15:25:26 
2006 +0000
@@ -0,0 +1,294 @@
+diff -pruN ../orig-linux-2.6.16.29/fs/aio.c ./fs/aio.c
+--- ../orig-linux-2.6.16.29/fs/aio.c   2006-09-12 19:02:10.000000000 +0100
++++ ./fs/aio.c 2006-09-19 13:58:49.000000000 +0100
+@@ -34,6 +34,11 @@
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+ 
++#ifdef CONFIG_EPOLL
++#include <linux/poll.h>
++#include <linux/eventpoll.h>
++#endif
++
+ #if DEBUG > 1
+ #define dprintk               printk
+ #else
+@@ -1016,6 +1021,10 @@ put_rq:
+       if (waitqueue_active(&ctx->wait))
+               wake_up(&ctx->wait);
+ 
++#ifdef CONFIG_EPOLL
++      if (ctx->file && waitqueue_active(&ctx->poll_wait))
++              wake_up(&ctx->poll_wait);
++#endif
+       if (ret)
+               put_ioctx(ctx);
+ 
+@@ -1025,6 +1034,8 @@ put_rq:
+ /* aio_read_evt
+  *    Pull an event off of the ioctx's event ring.  Returns the number of 
+  *    events fetched (0 or 1 ;-)
++ *    If ent parameter is 0, just returns the number of events that would
++ *    be fetched.
+  *    FIXME: make this use cmpxchg.
+  *    TODO: make the ringbuffer user mmap()able (requires FIXME).
+  */
+@@ -1047,13 +1058,18 @@ static int aio_read_evt(struct kioctx *i
+ 
+       head = ring->head % info->nr;
+       if (head != ring->tail) {
+-              struct io_event *evp = aio_ring_event(info, head, KM_USER1);
+-              *ent = *evp;
+-              head = (head + 1) % info->nr;
+-              smp_mb(); /* finish reading the event before updatng the head */
+-              ring->head = head;
+-              ret = 1;
+-              put_aio_ring_event(evp, KM_USER1);
++              if (ent) { /* event requested */
++                      struct io_event *evp =
++                              aio_ring_event(info, head, KM_USER1);
++                      *ent = *evp;
++                      head = (head + 1) % info->nr;
++                      /* finish reading the event before updatng the head */
++                      smp_mb();
++                      ring->head = head;
++                      ret = 1;
++                      put_aio_ring_event(evp, KM_USER1);
++              } else /* only need to know availability */
++                      ret = 1;
+       }
+       spin_unlock(&info->ring_lock);
+ 
+@@ -1236,9 +1252,78 @@ static void io_destroy(struct kioctx *io
+ 
+       aio_cancel_all(ioctx);
+       wait_for_all_aios(ioctx);
++#ifdef CONFIG_EPOLL
++      /* forget the poll file, but it's up to the user to close it */
++      if (ioctx->file) {
++              ioctx->file->private_data = 0;
++              ioctx->file = 0;
++      }
++#endif
+       put_ioctx(ioctx);       /* once for the lookup */
+ }
+ 
++#ifdef CONFIG_EPOLL
++
++static int aio_queue_fd_close(struct inode *inode, struct file *file)
++{
++      struct kioctx *ioctx = file->private_data;
++      if (ioctx) {
++              file->private_data = 0;
++              spin_lock_irq(&ioctx->ctx_lock);
++              ioctx->file = 0;
++              spin_unlock_irq(&ioctx->ctx_lock);
++      }
++      return 0;
++}
++
++static unsigned int aio_queue_fd_poll(struct file *file, poll_table *wait)
++{     unsigned int pollflags = 0;
++      struct kioctx *ioctx = file->private_data;
++
++      if (ioctx) {
++
++              spin_lock_irq(&ioctx->ctx_lock);
++              /* Insert inside our poll wait queue */
++              poll_wait(file, &ioctx->poll_wait, wait);
++
++              /* Check our condition */
++              if (aio_read_evt(ioctx, 0))
++                      pollflags = POLLIN | POLLRDNORM;
++              spin_unlock_irq(&ioctx->ctx_lock);
++      }
++
++      return pollflags;
++}
++
++static struct file_operations aioq_fops = {
++      .release        = aio_queue_fd_close,
++      .poll           = aio_queue_fd_poll
++};
++
++/* make_aio_fd:
++ *  Create a file descriptor that can be used to poll the event queue.
++ *  Based and piggybacked on the excellent epoll code.
++ */
++
++static int make_aio_fd(struct kioctx *ioctx)
++{
++      int error, fd;
++      struct inode *inode;
++      struct file *file;
++
++      error = ep_getfd(&fd, &inode, &file, NULL, &aioq_fops);
++      if (error)
++              return error;
++
++      /* associate the file with the IO context */
++      file->private_data = ioctx;
++      ioctx->file = file;
++      init_waitqueue_head(&ioctx->poll_wait);
++      return fd;
++}
++#endif
++
++
+ /* sys_io_setup:
+  *    Create an aio_context capable of receiving at least nr_events.
+  *    ctxp must not point to an aio_context that already exists, and
+@@ -1251,18 +1336,30 @@ static void io_destroy(struct kioctx *io
+  *    resources are available.  May fail with -EFAULT if an invalid
+  *    pointer is passed for ctxp.  Will fail with -ENOSYS if not
+  *    implemented.
++ *
++ *    To request a selectable fd, the user context has to be initialized
++ *    to 1, instead of 0, and the return value is the fd.
++ *    This keeps the system call compatible, since a non-zero value
++ *    was not allowed so far.
+  */
+ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp)
+ {
+       struct kioctx *ioctx = NULL;
+       unsigned long ctx;
+       long ret;
++      int make_fd = 0;
+ 
+       ret = get_user(ctx, ctxp);
+       if (unlikely(ret))
+               goto out;
+ 
+       ret = -EINVAL;
++#ifdef CONFIG_EPOLL
++      if (ctx == 1) {
++              make_fd = 1;
++              ctx = 0;
++      }
++#endif
+       if (unlikely(ctx || nr_events == 0)) {
+               pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
+                        ctx, nr_events);
+@@ -1273,8 +1370,12 @@ asmlinkage long sys_io_setup(unsigned nr
+       ret = PTR_ERR(ioctx);
+       if (!IS_ERR(ioctx)) {
+               ret = put_user(ioctx->user_id, ctxp);
+-              if (!ret)
+-                      return 0;
++#ifdef CONFIG_EPOLL
++              if (make_fd && ret >= 0)
++                      ret = make_aio_fd(ioctx);
++#endif
++              if (ret >= 0)
++                      return ret;
+ 
+               get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
+               io_destroy(ioctx);
+diff -pruN ../orig-linux-2.6.16.29/fs/eventpoll.c ./fs/eventpoll.c
+--- ../orig-linux-2.6.16.29/fs/eventpoll.c     2006-09-12 19:02:10.000000000 
+0100
++++ ./fs/eventpoll.c   2006-09-19 13:58:49.000000000 +0100
+@@ -235,8 +235,6 @@ struct ep_pqueue {
+ 
+ static void ep_poll_safewake_init(struct poll_safewake *psw);
+ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t 
*wq);
+-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+-                  struct eventpoll *ep);
+ static int ep_alloc(struct eventpoll **pep);
+ static void ep_free(struct eventpoll *ep);
+ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int 
fd);
+@@ -266,7 +264,7 @@ static int ep_events_transfer(struct eve
+ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
+                  int maxevents, long timeout);
+ static int eventpollfs_delete_dentry(struct dentry *dentry);
+-static struct inode *ep_eventpoll_inode(void);
++static struct inode *ep_eventpoll_inode(struct file_operations *fops);
+ static struct super_block *eventpollfs_get_sb(struct file_system_type 
*fs_type,
+                                             int flags, const char *dev_name,
+                                             void *data);
+@@ -525,7 +523,7 @@ asmlinkage long sys_epoll_create(int siz
+        * Creates all the items needed to setup an eventpoll file. That is,
+        * a file structure, and inode and a free file descriptor.
+        */
+-      error = ep_getfd(&fd, &inode, &file, ep);
++      error = ep_getfd(&fd, &inode, &file, ep, &eventpoll_fops);
+       if (error)
+               goto eexit_2;
+ 
+@@ -710,8 +708,8 @@ eexit_1:
+ /*
+  * Creates the file descriptor to be used by the epoll interface.
+  */
+-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+-                  struct eventpoll *ep)
++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
++                  struct eventpoll *ep, struct file_operations *fops)
+ {
+       struct qstr this;
+       char name[32];
+@@ -727,7 +725,7 @@ static int ep_getfd(int *efd, struct ino
+               goto eexit_1;
+ 
+       /* Allocates an inode from the eventpoll file system */
+-      inode = ep_eventpoll_inode();
++      inode = ep_eventpoll_inode(fops);
+       error = PTR_ERR(inode);
+       if (IS_ERR(inode))
+               goto eexit_2;
+@@ -758,7 +756,7 @@ static int ep_getfd(int *efd, struct ino
+ 
+       file->f_pos = 0;
+       file->f_flags = O_RDONLY;
+-      file->f_op = &eventpoll_fops;
++      file->f_op = fops;
+       file->f_mode = FMODE_READ;
+       file->f_version = 0;
+       file->private_data = ep;
+@@ -1574,7 +1572,7 @@ static int eventpollfs_delete_dentry(str
+ }
+ 
+ 
+-static struct inode *ep_eventpoll_inode(void)
++static struct inode *ep_eventpoll_inode(struct file_operations *fops)
+ {
+       int error = -ENOMEM;
+       struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
+@@ -1582,7 +1580,7 @@ static struct inode *ep_eventpoll_inode(
+       if (!inode)
+               goto eexit_1;
+ 
+-      inode->i_fop = &eventpoll_fops;
++      inode->i_fop = fops;
+ 
+       /*
+        * Mark the inode dirty from the very beginning,
+diff -pruN ../orig-linux-2.6.16.29/include/linux/aio.h ./include/linux/aio.h
+--- ../orig-linux-2.6.16.29/include/linux/aio.h        2006-09-12 
19:02:10.000000000 +0100
++++ ./include/linux/aio.h      2006-09-19 13:58:49.000000000 +0100
+@@ -191,6 +191,11 @@ struct kioctx {
+       struct aio_ring_info    ring_info;
+ 
+       struct work_struct      wq;
++#ifdef CONFIG_EPOLL
++      // poll integration
++      wait_queue_head_t       poll_wait;
++      struct file             *file;
++#endif
+ };
+ 
+ /* prototypes */
+diff -pruN ../orig-linux-2.6.16.29/include/linux/eventpoll.h 
./include/linux/eventpoll.h
+--- ../orig-linux-2.6.16.29/include/linux/eventpoll.h  2006-09-12 
19:02:10.000000000 +0100
++++ ./include/linux/eventpoll.h        2006-09-19 13:58:49.000000000 +0100
+@@ -86,6 +86,12 @@ static inline void eventpoll_release(str
+ }
+ 
+ 
++/*
++ * called by aio code to create fd that can poll the  aio event queueQ
++ */
++struct eventpoll;
++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
++             struct eventpoll *ep, struct file_operations *fops);
+ #else
+ 
+ static inline void eventpoll_init_file(struct file *file) {}
diff -r 7826e5482d42 -r 6c2c7ff6265a patches/linux-2.6.16.33/device_bind.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/device_bind.patch Tue Nov 28 15:25:26 2006 +0000
@@ -0,0 +1,15 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/base/bus.c ./drivers/base/bus.c
+--- ../orig-linux-2.6.16.29/drivers/base/bus.c 2006-09-12 19:02:10.000000000 
+0100
++++ ./drivers/base/bus.c       2006-09-19 13:58:54.000000000 +0100
+@@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device
+               up(&dev->sem);
+               if (dev->parent)
+                       up(&dev->parent->sem);
++
++              if (err > 0)            /* success */
++                      err = count;
++              else if (err == 0)      /* driver didn't accept device */
++                      err = -ENODEV;
+       }
+       put_device(dev);
+       put_bus(bus);
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/fix-hz-suspend.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/fix-hz-suspend.patch      Tue Nov 28 15:25:26 
2006 +0000
@@ -0,0 +1,26 @@
+diff -pruN ../orig-linux-2.6.16.29/kernel/timer.c ./kernel/timer.c
+--- ../orig-linux-2.6.16.29/kernel/timer.c     2006-09-12 19:02:10.000000000 
+0100
++++ ./kernel/timer.c   2006-09-19 13:58:58.000000000 +0100
+@@ -555,6 +555,22 @@ found:
+       }
+       spin_unlock(&base->t_base.lock);
+ 
++      /*
++       * It can happen that other CPUs service timer IRQs and increment
++       * jiffies, but we have not yet got a local timer tick to process
++       * the timer wheels.  In that case, the expiry time can be before
++       * jiffies, but since the high-resolution timer here is relative to
++       * jiffies, the default expression when high-resolution timers are
++       * not active,
++       *
++       *   time_before(MAX_JIFFY_OFFSET + jiffies, expires)
++       *
++       * would falsely evaluate to true.  If that is the case, just
++       * return jiffies so that we can immediately fire the local timer
++       */
++      if (time_before(expires, jiffies))
++              return jiffies;
++
+       if (time_before(hr_expires, expires))
+               return hr_expires;
+ 
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/fix-ide-cd-pio-mode.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/fix-ide-cd-pio-mode.patch Tue Nov 28 15:25:26 
2006 +0000
@@ -0,0 +1,18 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/ide/ide-lib.c 
./drivers/ide/ide-lib.c
+--- ../orig-linux-2.6.16.29/drivers/ide/ide-lib.c      2006-09-12 
19:02:10.000000000 +0100
++++ ./drivers/ide/ide-lib.c    2006-09-19 13:59:03.000000000 +0100
+@@ -410,10 +410,10 @@ void ide_toggle_bounce(ide_drive_t *driv
+ {
+       u64 addr = BLK_BOUNCE_HIGH;     /* dma64_addr_t */
+ 
+-      if (!PCI_DMA_BUS_IS_PHYS) {
+-              addr = BLK_BOUNCE_ANY;
+-      } else if (on && drive->media == ide_disk) {
+-              if (HWIF(drive)->pci_dev)
++      if (on && drive->media == ide_disk) {
++              if (!PCI_DMA_BUS_IS_PHYS)
++                      addr = BLK_BOUNCE_ANY;
++              else if (HWIF(drive)->pci_dev)
+                       addr = HWIF(drive)->pci_dev->dma_mask;
+       }
+ 
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/i386-mach-io-check-nmi.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/i386-mach-io-check-nmi.patch      Tue Nov 28 
15:25:26 2006 +0000
@@ -0,0 +1,45 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/traps.c 
./arch/i386/kernel/traps.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/traps.c   2006-09-12 
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/traps.c 2006-09-19 13:59:06.000000000 +0100
+@@ -567,18 +567,11 @@ static void mem_parity_error(unsigned ch
+ 
+ static void io_check_error(unsigned char reason, struct pt_regs * regs)
+ {
+-      unsigned long i;
+-
+       printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
+       show_registers(regs);
+ 
+       /* Re-enable the IOCK line, wait for a few seconds */
+-      reason = (reason & 0xf) | 8;
+-      outb(reason, 0x61);
+-      i = 2000;
+-      while (--i) udelay(1000);
+-      reason &= ~8;
+-      outb(reason, 0x61);
++      clear_io_check_error(reason);
+ }
+ 
+ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/mach-default/mach_traps.h 
./include/asm-i386/mach-default/mach_traps.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/mach-default/mach_traps.h 
2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/mach-default/mach_traps.h       2006-09-19 
13:59:06.000000000 +0100
+@@ -15,6 +15,18 @@ static inline void clear_mem_error(unsig
+       outb(reason, 0x61);
+ }
+ 
++static inline void clear_io_check_error(unsigned char reason)
++{
++      unsigned long i;
++
++      reason = (reason & 0xf) | 8;
++      outb(reason, 0x61);
++      i = 2000;
++      while (--i) udelay(1000);
++      reason &= ~8;
++      outb(reason, 0x61);
++}
++
+ static inline unsigned char get_nmi_reason(void)
+ {
+       return inb(0x61);
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/ipv6-no-autoconf.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/ipv6-no-autoconf.patch    Tue Nov 28 15:25:26 
2006 +0000
@@ -0,0 +1,19 @@
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/addrconf.c ./net/ipv6/addrconf.c
+--- ../orig-linux-2.6.16.29/net/ipv6/addrconf.c        2006-09-12 
19:02:10.000000000 +0100
++++ ./net/ipv6/addrconf.c      2006-09-19 13:59:11.000000000 +0100
+@@ -2471,6 +2471,7 @@ static void addrconf_dad_start(struct in
+       spin_lock_bh(&ifp->lock);
+ 
+       if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
++          !(dev->flags&IFF_MULTICAST) ||
+           !(ifp->flags&IFA_F_TENTATIVE)) {
+               ifp->flags &= ~IFA_F_TENTATIVE;
+               spin_unlock_bh(&ifp->lock);
+@@ -2555,6 +2556,7 @@ static void addrconf_dad_completed(struc
+       if (ifp->idev->cnf.forwarding == 0 &&
+           ifp->idev->cnf.rtr_solicits > 0 &&
+           (dev->flags&IFF_LOOPBACK) == 0 &&
++          (dev->flags & IFF_MULTICAST) &&
+           (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
+               struct in6_addr all_routers;
+ 
diff -r 7826e5482d42 -r 6c2c7ff6265a patches/linux-2.6.16.33/kasprintf.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/kasprintf.patch   Tue Nov 28 15:25:26 2006 +0000
@@ -0,0 +1,59 @@
+commit e905914f96e11862b130dd229f73045dad9a34e8
+Author: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
+Date:   Sun Jun 25 05:49:17 2006 -0700
+
+    [PATCH] Implement kasprintf
+    
+    Implement kasprintf, a kernel version of asprintf.  This allocates the
+    memory required for the formatted string, including the trailing '\0'.
+    Returns NULL on allocation failure.
+    
+    Signed-off-by: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
+    Signed-off-by: Chris Wright <chrisw@xxxxxxxxxxxx>
+    Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
+    Signed-off-by: Linus Torvalds <torvalds@xxxxxxxx>
+
+diff --git a/include/linux/kernel.h b/include/linux/kernel.h
+index 8c21aaa..3c5e4c2 100644
+--- a/include/linux/kernel.h
++++ b/include/linux/kernel.h
+@@ -117,6 +117,8 @@ extern int scnprintf(char * buf, size_t
+       __attribute__ ((format (printf, 3, 4)));
+ extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 3, 0)));
++extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
++      __attribute__ ((format (printf, 2, 3)));
+ 
+ extern int sscanf(const char *, const char *, ...)
+       __attribute__ ((format (scanf, 2, 3)));
+diff --git a/lib/vsprintf.c b/lib/vsprintf.c
+index f595947..797428a 100644
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -849,3 +849,26 @@ int sscanf(const char * buf, const char
+ }
+ 
+ EXPORT_SYMBOL(sscanf);
++
++
++/* Simplified asprintf. */
++char *kasprintf(gfp_t gfp, const char *fmt, ...)
++{
++      va_list ap;
++      unsigned int len;
++      char *p;
++
++      va_start(ap, fmt);
++      len = vsnprintf(NULL, 0, fmt, ap);
++      va_end(ap);
++
++      p = kmalloc(len+1, gfp);
++      if (!p)
++              return NULL;
++      va_start(ap, fmt);
++      vsnprintf(p, len+1, fmt, ap);
++      va_end(ap);
++      return p;
++}
++
++EXPORT_SYMBOL(kasprintf);
diff -r 7826e5482d42 -r 6c2c7ff6265a patches/linux-2.6.16.33/net-csum.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/net-csum.patch    Tue Nov 28 15:25:26 2006 +0000
@@ -0,0 +1,63 @@
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_tcp.c 
./net/ipv4/netfilter/ip_nat_proto_tcp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_tcp.c      
2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c    2006-09-19 13:59:15.000000000 
+0100
+@@ -129,7 +129,12 @@ tcp_manip_pkt(struct sk_buff **pskb,
+       if (hdrsize < sizeof(*hdr))
+               return 1;
+ 
+-      hdr->check = ip_nat_cheat_check(~oldip, newip,
++#ifdef CONFIG_XEN
++      if ((*pskb)->proto_csum_blank)
++              hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check);
++      else
++#endif
++              hdr->check = ip_nat_cheat_check(~oldip, newip,
+                                       ip_nat_cheat_check(oldport ^ 0xFFFF,
+                                                          newport,
+                                                          hdr->check));
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_udp.c 
./net/ipv4/netfilter/ip_nat_proto_udp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_udp.c      
2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/netfilter/ip_nat_proto_udp.c    2006-09-19 13:59:15.000000000 
+0100
+@@ -113,11 +113,17 @@ udp_manip_pkt(struct sk_buff **pskb,
+               newport = tuple->dst.u.udp.port;
+               portptr = &hdr->dest;
+       }
+-      if (hdr->check) /* 0 is a special case meaning no checksum */
+-              hdr->check = ip_nat_cheat_check(~oldip, newip,
++      if (hdr->check) { /* 0 is a special case meaning no checksum */
++#ifdef CONFIG_XEN
++              if ((*pskb)->proto_csum_blank)
++                      hdr->check = ip_nat_cheat_check(oldip, ~newip, 
hdr->check);
++              else
++#endif
++                      hdr->check = ip_nat_cheat_check(~oldip, newip,
+                                       ip_nat_cheat_check(*portptr ^ 0xFFFF,
+                                                          newport,
+                                                          hdr->check));
++      }
+       *portptr = newport;
+       return 1;
+ }
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c 
./net/ipv4/xfrm4_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c    2006-09-12 
19:02:10.000000000 +0100
++++ ./net/ipv4/xfrm4_output.c  2006-09-19 13:59:15.000000000 +0100
+@@ -17,6 +17,8 @@
+ #include <net/xfrm.h>
+ #include <net/icmp.h>
+ 
++extern int skb_checksum_setup(struct sk_buff *skb);
++
+ /* Add encapsulation header.
+  *
+  * In transport mode, the IP header will be moved forward to make space
+@@ -103,6 +105,10 @@ static int xfrm4_output_one(struct sk_bu
+       struct xfrm_state *x = dst->xfrm;
+       int err;
+       
++      err = skb_checksum_setup(skb);
++      if (err)
++              goto error_nolock;
++
+       if (skb->ip_summed == CHECKSUM_HW) {
+               err = skb_checksum_help(skb, 0);
+               if (err)
diff -r 7826e5482d42 -r 6c2c7ff6265a 
patches/linux-2.6.16.33/net-gso-0-base.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.33/net-gso-0-base.patch      Tue Nov 28 15:25:26 
2006 +0000
@@ -0,0 +1,2898 @@
+Index: tmp-xxx/Documentation/networking/netdevices.txt
+===================================================================
+--- tmp-xxx.orig/Documentation/networking/netdevices.txt       2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/Documentation/networking/netdevices.txt    2006-11-27 
10:52:42.000000000 +0000
+@@ -42,9 +42,9 @@
+       Context: nominally process, but don't sleep inside an rwlock
+ 
+ dev->hard_start_xmit:
+-      Synchronization: dev->xmit_lock spinlock.
++      Synchronization: netif_tx_lock spinlock.
+       When the driver sets NETIF_F_LLTX in dev->features this will be
+-      called without holding xmit_lock. In this case the driver 
++      called without holding netif_tx_lock. In this case the driver
+       has to lock by itself when needed. It is recommended to use a try lock
+       for this and return -1 when the spin lock fails. 
+       The locking there should also properly protect against 
+@@ -62,12 +62,12 @@
+         Only valid when NETIF_F_LLTX is set.
+ 
+ dev->tx_timeout:
+-      Synchronization: dev->xmit_lock spinlock.
++      Synchronization: netif_tx_lock spinlock.
+       Context: BHs disabled
+       Notes: netif_queue_stopped() is guaranteed true
+ 
+ dev->set_multicast_list:
+-      Synchronization: dev->xmit_lock spinlock.
++      Synchronization: netif_tx_lock spinlock.
+       Context: BHs disabled
+ 
+ dev->poll:
+Index: tmp-xxx/drivers/block/aoe/aoenet.c
+===================================================================
+--- tmp-xxx.orig/drivers/block/aoe/aoenet.c    2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/block/aoe/aoenet.c 2006-11-27 10:52:42.000000000 +0000
+@@ -95,9 +95,8 @@
+ static struct sk_buff *
+ skb_check(struct sk_buff *skb)
+ {
+-      if (skb_is_nonlinear(skb))
+       if ((skb = skb_share_check(skb, GFP_ATOMIC)))
+-      if (skb_linearize(skb, GFP_ATOMIC) < 0) {
++      if (skb_linearize(skb)) {
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+Index: tmp-xxx/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+===================================================================
+--- tmp-xxx.orig/drivers/infiniband/ulp/ipoib/ipoib_multicast.c        
2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/infiniband/ulp/ipoib/ipoib_multicast.c     2006-11-27 
10:52:42.000000000 +0000
+@@ -821,7 +821,8 @@
+ 
+       ipoib_mcast_stop_thread(dev, 0);
+ 
+-      spin_lock_irqsave(&dev->xmit_lock, flags);
++      local_irq_save(flags);
++      netif_tx_lock(dev);
+       spin_lock(&priv->lock);
+ 
+       /*
+@@ -896,7 +897,8 @@
+       }
+ 
+       spin_unlock(&priv->lock);
+-      spin_unlock_irqrestore(&dev->xmit_lock, flags);
++      netif_tx_unlock(dev);
++      local_irq_restore(flags);
+ 
+       /* We have to cancel outside of the spinlock */
+       list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
+Index: tmp-xxx/drivers/media/dvb/dvb-core/dvb_net.c
+===================================================================
+--- tmp-xxx.orig/drivers/media/dvb/dvb-core/dvb_net.c  2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/drivers/media/dvb/dvb-core/dvb_net.c       2006-11-27 
10:52:42.000000000 +0000
+@@ -1053,7 +1053,7 @@
+ 
+       dvb_net_feed_stop(dev);
+       priv->rx_mode = RX_MODE_UNI;
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+ 
+       if (dev->flags & IFF_PROMISC) {
+               dprintk("%s: promiscuous mode\n", dev->name);
+@@ -1078,7 +1078,7 @@
+               }
+       }
+ 
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+       dvb_net_feed_start(dev);
+ }
+ 
+Index: tmp-xxx/drivers/net/8139cp.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/8139cp.c  2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/8139cp.c       2006-11-27 10:52:42.000000000 +0000
+@@ -794,7 +794,7 @@
+       entry = cp->tx_head;
+       eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+       if (dev->features & NETIF_F_TSO)
+-              mss = skb_shinfo(skb)->tso_size;
++              mss = skb_shinfo(skb)->gso_size;
+ 
+       if (skb_shinfo(skb)->nr_frags == 0) {
+               struct cp_desc *txd = &cp->tx_ring[entry];
+Index: tmp-xxx/drivers/net/bnx2.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/bnx2.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/bnx2.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1593,7 +1593,7 @@
+               skb = tx_buf->skb;
+ #ifdef BCM_TSO 
+               /* partial BD completions possible with TSO packets */
+-              if (skb_shinfo(skb)->tso_size) {
++              if (skb_shinfo(skb)->gso_size) {
+                       u16 last_idx, last_ring_idx;
+ 
+                       last_idx = sw_cons +
+@@ -1948,7 +1948,7 @@
+       return 1;
+ }
+ 
+-/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
++/* Called with rtnl_lock from vlan functions and also netif_tx_lock
+  * from set_multicast.
+  */
+ static void
+@@ -4403,7 +4403,7 @@
+ }
+ #endif
+ 
+-/* Called with dev->xmit_lock.
++/* Called with netif_tx_lock.
+  * hard_start_xmit is pseudo-lockless - a lock is only required when
+  * the tx queue is full. This way, we get the benefit of lockless
+  * operations most of the time without the complexities to handle
+@@ -4441,7 +4441,7 @@
+                       (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
+       }
+ #ifdef BCM_TSO 
+-      if ((mss = skb_shinfo(skb)->tso_size) &&
++      if ((mss = skb_shinfo(skb)->gso_size) &&
+               (skb->len > (bp->dev->mtu + ETH_HLEN))) {
+               u32 tcp_opt_len, ip_tcp_len;
+ 
+Index: tmp-xxx/drivers/net/bonding/bond_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/bonding/bond_main.c       2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/bonding/bond_main.c    2006-11-27 10:52:42.000000000 
+0000
+@@ -1145,8 +1145,7 @@
+ }
+ 
+ #define BOND_INTERSECT_FEATURES \
+-      (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM|\
+-      NETIF_F_TSO|NETIF_F_UFO)
++      (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
+ 
+ /* 
+  * Compute the common dev->feature set available to all slaves.  Some
+@@ -1164,9 +1163,7 @@
+               features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+ 
+       if ((features & NETIF_F_SG) && 
+-          !(features & (NETIF_F_IP_CSUM |
+-                        NETIF_F_NO_CSUM |
+-                        NETIF_F_HW_CSUM)))
++          !(features & NETIF_F_ALL_CSUM))
+               features &= ~NETIF_F_SG;
+ 
+       /* 
+@@ -4147,7 +4144,7 @@
+        */
+       bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
+ 
+-      /* don't acquire bond device's xmit_lock when 
++      /* don't acquire bond device's netif_tx_lock when
+        * transmitting */
+       bond_dev->features |= NETIF_F_LLTX;
+ 
+Index: tmp-xxx/drivers/net/chelsio/sge.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/chelsio/sge.c     2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/chelsio/sge.c  2006-11-27 10:52:42.000000000 +0000
+@@ -1419,7 +1419,7 @@
+       struct cpl_tx_pkt *cpl;
+ 
+ #ifdef NETIF_F_TSO
+-      if (skb_shinfo(skb)->tso_size) {
++      if (skb_shinfo(skb)->gso_size) {
+               int eth_type;
+               struct cpl_tx_pkt_lso *hdr;
+ 
+@@ -1434,7 +1434,7 @@
+               hdr->ip_hdr_words = skb->nh.iph->ihl;
+               hdr->tcp_hdr_words = skb->h.th->doff;
+               hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
+-                                              skb_shinfo(skb)->tso_size));
++                                              skb_shinfo(skb)->gso_size));
+               hdr->len = htonl(skb->len - sizeof(*hdr));
+               cpl = (struct cpl_tx_pkt *)hdr;
+               sge->stats.tx_lso_pkts++;
+Index: tmp-xxx/drivers/net/e1000/e1000_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/e1000/e1000_main.c        2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/e1000/e1000_main.c     2006-11-27 10:52:42.000000000 
+0000
+@@ -2526,7 +2526,7 @@
+       uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
+       int err;
+ 
+-      if (skb_shinfo(skb)->tso_size) {
++      if (skb_shinfo(skb)->gso_size) {
+               if (skb_header_cloned(skb)) {
+                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                       if (err)
+@@ -2534,7 +2534,7 @@
+               }
+ 
+               hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+-              mss = skb_shinfo(skb)->tso_size;
++              mss = skb_shinfo(skb)->gso_size;
+               if (skb->protocol == ntohs(ETH_P_IP)) {
+                       skb->nh.iph->tot_len = 0;
+                       skb->nh.iph->check = 0;
+@@ -2651,7 +2651,7 @@
+                * tso gets written back prematurely before the data is fully
+                * DMAd to the controller */
+               if (!skb->data_len && tx_ring->last_tx_tso &&
+-                              !skb_shinfo(skb)->tso_size) {
++                              !skb_shinfo(skb)->gso_size) {
+                       tx_ring->last_tx_tso = 0;
+                       size -= 4;
+               }
+@@ -2893,7 +2893,7 @@
+       }
+ 
+ #ifdef NETIF_F_TSO
+-      mss = skb_shinfo(skb)->tso_size;
++      mss = skb_shinfo(skb)->gso_size;
+       /* The controller does a simple calculation to 
+        * make sure there is enough room in the FIFO before
+        * initiating the DMA for each buffer.  The calc is:
+@@ -2935,7 +2935,7 @@
+ #ifdef NETIF_F_TSO
+       /* Controller Erratum workaround */
+       if (!skb->data_len && tx_ring->last_tx_tso &&
+-              !skb_shinfo(skb)->tso_size)
++              !skb_shinfo(skb)->gso_size)
+               count++;
+ #endif
+ 
+Index: tmp-xxx/drivers/net/forcedeth.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/forcedeth.c       2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/forcedeth.c    2006-11-27 10:52:42.000000000 +0000
+@@ -482,9 +482,9 @@
+  * critical parts:
+  * - rx is (pseudo-) lockless: it relies on the single-threading provided
+  *    by the arch code for interrupts.
+- * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission
++ * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
+  *    needs dev->priv->lock :-(
+- * - set_multicast_list: preparation lockless, relies on dev->xmit_lock.
++ * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
+  */
+ 
+ /* in dev: base, irq */
+@@ -1016,7 +1016,7 @@
+ 
+ /*
+  * nv_start_xmit: dev->hard_start_xmit function
+- * Called with dev->xmit_lock held.
++ * Called with netif_tx_lock held.
+  */
+ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -1105,8 +1105,8 @@
+       np->tx_skbuff[nr] = skb;
+ 
+ #ifdef NETIF_F_TSO
+-      if (skb_shinfo(skb)->tso_size)
+-              tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << 
NV_TX2_TSO_SHIFT);
++      if (skb_shinfo(skb)->gso_size)
++              tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << 
NV_TX2_TSO_SHIFT);
+       else
+ #endif
+       tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? 
(NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+@@ -1203,7 +1203,7 @@
+ 
+ /*
+  * nv_tx_timeout: dev->tx_timeout function
+- * Called with dev->xmit_lock held.
++ * Called with netif_tx_lock held.
+  */
+ static void nv_tx_timeout(struct net_device *dev)
+ {
+@@ -1524,7 +1524,7 @@
+                * Changing the MTU is a rare event, it shouldn't matter.
+                */
+               disable_irq(dev->irq);
+-              spin_lock_bh(&dev->xmit_lock);
++              netif_tx_lock_bh(dev);
+               spin_lock(&np->lock);
+               /* stop engines */
+               nv_stop_rx(dev);
+@@ -1559,7 +1559,7 @@
+               nv_start_rx(dev);
+               nv_start_tx(dev);
+               spin_unlock(&np->lock);
+-              spin_unlock_bh(&dev->xmit_lock);
++              netif_tx_unlock_bh(dev);
+               enable_irq(dev->irq);
+       }
+       return 0;
+@@ -1594,7 +1594,7 @@
+       memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
+ 
+       if (netif_running(dev)) {
+-              spin_lock_bh(&dev->xmit_lock);
++              netif_tx_lock_bh(dev);
+               spin_lock_irq(&np->lock);
+ 
+               /* stop rx engine */
+@@ -1606,7 +1606,7 @@
+               /* restart rx engine */
+               nv_start_rx(dev);
+               spin_unlock_irq(&np->lock);
+-              spin_unlock_bh(&dev->xmit_lock);
++              netif_tx_unlock_bh(dev);
+       } else {
+               nv_copy_mac_to_hw(dev);
+       }
+@@ -1615,7 +1615,7 @@
+ 
+ /*
+  * nv_set_multicast: dev->set_multicast function
+- * Called with dev->xmit_lock held.
++ * Called with netif_tx_lock held.
+  */
+ static void nv_set_multicast(struct net_device *dev)
+ {
+Index: tmp-xxx/drivers/net/hamradio/6pack.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/hamradio/6pack.c  2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/hamradio/6pack.c       2006-11-27 10:52:42.000000000 
+0000
+@@ -308,9 +308,9 @@
+ {
+       struct sockaddr_ax25 *sa = addr;
+ 
+-      spin_lock_irq(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+-      spin_unlock_irq(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+ 
+       return 0;
+ }
+@@ -767,9 +767,9 @@
+                       break;
+               }
+ 
+-              spin_lock_irq(&dev->xmit_lock);
++              netif_tx_lock_bh(dev);
+               memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
+-              spin_unlock_irq(&dev->xmit_lock);
++              netif_tx_unlock_bh(dev);
+ 
+               err = 0;
+               break;
+Index: tmp-xxx/drivers/net/hamradio/mkiss.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/hamradio/mkiss.c  2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/hamradio/mkiss.c       2006-11-27 10:52:42.000000000 
+0000
+@@ -357,9 +357,9 @@
+ {
+       struct sockaddr_ax25 *sa = addr;
+ 
+-      spin_lock_irq(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+-      spin_unlock_irq(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+ 
+       return 0;
+ }
+@@ -886,9 +886,9 @@
+                       break;
+               }
+ 
+-              spin_lock_irq(&dev->xmit_lock);
++              netif_tx_lock_bh(dev);
+               memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
+-              spin_unlock_irq(&dev->xmit_lock);
++              netif_tx_unlock_bh(dev);
+ 
+               err = 0;
+               break;
+Index: tmp-xxx/drivers/net/ifb.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/ifb.c     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/ifb.c  2006-11-27 10:52:42.000000000 +0000
+@@ -76,13 +76,13 @@
+       dp->st_task_enter++;
+       if ((skb = skb_peek(&dp->tq)) == NULL) {
+               dp->st_txq_refl_try++;
+-              if (spin_trylock(&_dev->xmit_lock)) {
++              if (netif_tx_trylock(_dev)) {
+                       dp->st_rxq_enter++;
+                       while ((skb = skb_dequeue(&dp->rq)) != NULL) {
+                               skb_queue_tail(&dp->tq, skb);
+                               dp->st_rx2tx_tran++;
+                       }
+-                      spin_unlock(&_dev->xmit_lock);
++                      netif_tx_unlock(_dev);
+               } else {
+                       /* reschedule */
+                       dp->st_rxq_notenter++;
+@@ -110,7 +110,7 @@
+               }
+       }
+ 
+-      if (spin_trylock(&_dev->xmit_lock)) {
++      if (netif_tx_trylock(_dev)) {
+               dp->st_rxq_check++;
+               if ((skb = skb_peek(&dp->rq)) == NULL) {
+                       dp->tasklet_pending = 0;
+@@ -118,10 +118,10 @@
+                               netif_wake_queue(_dev);
+               } else {
+                       dp->st_rxq_rsch++;
+-                      spin_unlock(&_dev->xmit_lock);
++                      netif_tx_unlock(_dev);
+                       goto resched;
+               }
+-              spin_unlock(&_dev->xmit_lock);
++              netif_tx_unlock(_dev);
+       } else {
+ resched:
+               dp->tasklet_pending = 1;
+Index: tmp-xxx/drivers/net/irda/vlsi_ir.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/irda/vlsi_ir.c    2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/irda/vlsi_ir.c 2006-11-27 10:52:42.000000000 +0000
+@@ -959,7 +959,7 @@
+                           ||  (now.tv_sec==ready.tv_sec && 
now.tv_usec>=ready.tv_usec))
+                               break;
+                       udelay(100);
+-                      /* must not sleep here - we are called under xmit_lock! 
*/
++                      /* must not sleep here - called under netif_tx_lock! */
+               }
+       }
+ 
+Index: tmp-xxx/drivers/net/ixgb/ixgb_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/ixgb/ixgb_main.c  2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/ixgb/ixgb_main.c       2006-11-27 10:52:42.000000000 
+0000
+@@ -1163,7 +1163,7 @@
+       uint16_t ipcse, tucse, mss;
+       int err;
+ 
+-      if(likely(skb_shinfo(skb)->tso_size)) {
++      if(likely(skb_shinfo(skb)->gso_size)) {
+               if (skb_header_cloned(skb)) {
+                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                       if (err)
+@@ -1171,7 +1171,7 @@
+               }
+ 
+               hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+-              mss = skb_shinfo(skb)->tso_size;
++              mss = skb_shinfo(skb)->gso_size;
+               skb->nh.iph->tot_len = 0;
+               skb->nh.iph->check = 0;
+               skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+Index: tmp-xxx/drivers/net/loopback.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/loopback.c        2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/loopback.c     2006-11-27 10:52:42.000000000 +0000
+@@ -74,7 +74,7 @@
+       struct iphdr *iph = skb->nh.iph;
+       struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
+       unsigned int doffset = (iph->ihl + th->doff) * 4;
+-      unsigned int mtu = skb_shinfo(skb)->tso_size + doffset;
++      unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
+       unsigned int offset = 0;
+       u32 seq = ntohl(th->seq);
+       u16 id  = ntohs(iph->id);
+@@ -139,7 +139,7 @@
+ #endif
+ 
+ #ifdef LOOPBACK_TSO
+-      if (skb_shinfo(skb)->tso_size) {
++      if (skb_shinfo(skb)->gso_size) {
+               BUG_ON(skb->protocol != htons(ETH_P_IP));
+               BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
+ 
+Index: tmp-xxx/drivers/net/mv643xx_eth.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/mv643xx_eth.c     2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/mv643xx_eth.c  2006-11-27 10:52:42.000000000 +0000
+@@ -1107,7 +1107,7 @@
+ 
+ #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+       if (has_tiny_unaligned_frags(skb)) {
+-              if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
++              if (__skb_linearize(skb)) {
+                       stats->tx_dropped++;
+                       printk(KERN_DEBUG "%s: failed to linearize tiny "
+                                       "unaligned fragment\n", dev->name);
+Index: tmp-xxx/drivers/net/natsemi.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/natsemi.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/natsemi.c      2006-11-27 10:52:42.000000000 +0000
+@@ -323,12 +323,12 @@
+ The rx process only runs in the interrupt handler. Access from outside
+ the interrupt handler is only permitted after disable_irq().
+ 
+-The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
++The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
+ is set, then access is permitted under spin_lock_irq(&np->lock).
+ 
+ Thus configuration functions that want to access everything must call
+       disable_irq(dev->irq);
+-      spin_lock_bh(dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       spin_lock_irq(&np->lock);
+ 
+ IV. Notes
+Index: tmp-xxx/drivers/net/r8169.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/r8169.c   2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/r8169.c        2006-11-27 10:52:42.000000000 +0000
+@@ -2171,7 +2171,7 @@
+ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device 
*dev)
+ {
+       if (dev->features & NETIF_F_TSO) {
+-              u32 mss = skb_shinfo(skb)->tso_size;
++              u32 mss = skb_shinfo(skb)->gso_size;
+ 
+               if (mss)
+                       return LargeSend | ((mss & MSSMask) << MSSShift);
+Index: tmp-xxx/drivers/net/s2io.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/s2io.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/s2io.c 2006-11-27 10:52:42.000000000 +0000
+@@ -3522,8 +3522,8 @@
+       txdp->Control_1 = 0;
+       txdp->Control_2 = 0;
+ #ifdef NETIF_F_TSO
+-      mss = skb_shinfo(skb)->tso_size;
+-      if (mss) {
++      mss = skb_shinfo(skb)->gso_size;
++      if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
+               txdp->Control_1 |= TXD_TCP_LSO_EN;
+               txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
+       }
+@@ -3543,10 +3543,10 @@
+       }
+ 
+       frg_len = skb->len - skb->data_len;
+-      if (skb_shinfo(skb)->ufo_size) {
++      if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
+               int ufo_size;
+ 
+-              ufo_size = skb_shinfo(skb)->ufo_size;
++              ufo_size = skb_shinfo(skb)->gso_size;
+               ufo_size &= ~7;
+               txdp->Control_1 |= TXD_UFO_EN;
+               txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
+@@ -3572,7 +3572,7 @@
+       txdp->Host_Control = (unsigned long) skb;
+       txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
+ 
+-      if (skb_shinfo(skb)->ufo_size)
++      if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+               txdp->Control_1 |= TXD_UFO_EN;
+ 
+       frg_cnt = skb_shinfo(skb)->nr_frags;
+@@ -3587,12 +3587,12 @@
+                   (sp->pdev, frag->page, frag->page_offset,
+                    frag->size, PCI_DMA_TODEVICE);
+               txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
+-              if (skb_shinfo(skb)->ufo_size)
++              if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+                       txdp->Control_1 |= TXD_UFO_EN;
+       }
+       txdp->Control_1 |= TXD_GATHER_CODE_LAST;
+ 
+-      if (skb_shinfo(skb)->ufo_size)
++      if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+               frg_cnt++; /* as Txd0 was used for inband header */
+ 
+       tx_fifo = mac_control->tx_FIFO_start[queue];
+@@ -3606,7 +3606,7 @@
+       if (mss)
+               val64 |= TX_FIFO_SPECIAL_FUNC;
+ #endif
+-      if (skb_shinfo(skb)->ufo_size)
++      if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+               val64 |= TX_FIFO_SPECIAL_FUNC;
+       writeq(val64, &tx_fifo->List_Control);
+ 
+Index: tmp-xxx/drivers/net/sky2.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/sky2.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/sky2.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1141,7 +1141,7 @@
+       count = sizeof(dma_addr_t) / sizeof(u32);
+       count += skb_shinfo(skb)->nr_frags * count;
+ 
+-      if (skb_shinfo(skb)->tso_size)
++      if (skb_shinfo(skb)->gso_size)
+               ++count;
+ 
+       if (skb->ip_summed == CHECKSUM_HW)
+@@ -1213,7 +1213,7 @@
+       }
+ 
+       /* Check for TCP Segmentation Offload */
+-      mss = skb_shinfo(skb)->tso_size;
++      mss = skb_shinfo(skb)->gso_size;
+       if (mss != 0) {
+               /* just drop the packet if non-linear expansion fails */
+               if (skb_header_cloned(skb) &&
+Index: tmp-xxx/drivers/net/tg3.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/tg3.c     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/tg3.c  2006-11-27 10:52:42.000000000 +0000
+@@ -3664,7 +3664,7 @@
+ #if TG3_TSO_SUPPORT != 0
+       mss = 0;
+       if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
+-          (mss = skb_shinfo(skb)->tso_size) != 0) {
++          (mss = skb_shinfo(skb)->gso_size) != 0) {
+               int tcp_opt_len, ip_tcp_len;
+ 
+               if (skb_header_cloned(skb) &&
+Index: tmp-xxx/drivers/net/tulip/winbond-840.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/tulip/winbond-840.c       2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/tulip/winbond-840.c    2006-11-27 10:52:42.000000000 
+0000
+@@ -1605,11 +1605,11 @@
+  * - get_stats:
+  *    spin_lock_irq(np->lock), doesn't touch hw if not present
+  * - hard_start_xmit:
+- *    netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
++ *    synchronize_irq + netif_tx_disable;
+  * - tx_timeout:
+- *    netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
++ *    netif_device_detach + netif_tx_disable;
+  * - set_multicast_list
+- *    netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
++ *    netif_device_detach + netif_tx_disable;
+  * - interrupt handler
+  *    doesn't touch hw if not present, synchronize_irq waits for
+  *    running instances of the interrupt handler.
+@@ -1635,11 +1635,10 @@
+               netif_device_detach(dev);
+               update_csr6(dev, 0);
+               iowrite32(0, ioaddr + IntrEnable);
+-              netif_stop_queue(dev);
+               spin_unlock_irq(&np->lock);
+ 
+-              spin_unlock_wait(&dev->xmit_lock);
+               synchronize_irq(dev->irq);
++              netif_tx_disable(dev);
+       
+               np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 
0xffff;
+ 
+Index: tmp-xxx/drivers/net/typhoon.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/typhoon.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/typhoon.c      2006-11-27 10:52:42.000000000 +0000
+@@ -340,7 +340,7 @@
+ #endif
+ 
+ #if defined(NETIF_F_TSO)
+-#define skb_tso_size(x)               (skb_shinfo(x)->tso_size)
++#define skb_tso_size(x)               (skb_shinfo(x)->gso_size)
+ #define TSO_NUM_DESCRIPTORS   2
+ #define TSO_OFFLOAD_ON                TYPHOON_OFFLOAD_TCP_SEGMENT
+ #else
+Index: tmp-xxx/drivers/net/via-velocity.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/via-velocity.c    2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/net/via-velocity.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1905,6 +1905,13 @@
+ 
+       int pktlen = skb->len;
+ 
++#ifdef VELOCITY_ZERO_COPY_SUPPORT
++      if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
++              kfree_skb(skb);
++              return 0;
++      }
++#endif
++
+       spin_lock_irqsave(&vptr->lock, flags);
+ 
+       index = vptr->td_curr[qnum];
+@@ -1920,8 +1927,6 @@
+        */
+       if (pktlen < ETH_ZLEN) {
+               /* Cannot occur until ZC support */
+-              if(skb_linearize(skb, GFP_ATOMIC))
+-                      return 0; 
+               pktlen = ETH_ZLEN;
+               memcpy(tdinfo->buf, skb->data, skb->len);
+               memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
+@@ -1939,7 +1944,6 @@
+               int nfrags = skb_shinfo(skb)->nr_frags;
+               tdinfo->skb = skb;
+               if (nfrags > 6) {
+-                      skb_linearize(skb, GFP_ATOMIC);
+                       memcpy(tdinfo->buf, skb->data, skb->len);
+                       tdinfo->skb_dma[0] = tdinfo->buf_dma;
+                       td_ptr->tdesc0.pktsize = 
+Index: tmp-xxx/drivers/net/wireless/orinoco.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/wireless/orinoco.c        2006-11-15 
10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/wireless/orinoco.c     2006-11-27 10:52:42.000000000 
+0000
+@@ -1835,7 +1835,9 @@
+       /* Set promiscuity / multicast*/
+       priv->promiscuous = 0;
+       priv->mc_count = 0;
+-      __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
++
++      /* FIXME: what about netif_tx_lock */
++      __orinoco_set_multicast_list(dev);
+ 
+       return 0;
+ }
+Index: tmp-xxx/drivers/s390/net/qeth_eddp.c
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_eddp.c  2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/s390/net/qeth_eddp.c       2006-11-27 10:52:42.000000000 
+0000
+@@ -421,7 +421,7 @@
+        }
+       tcph = eddp->skb->h.th;
+       while (eddp->skb_offset < eddp->skb->len) {
+-              data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
++              data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
+                              (int)(eddp->skb->len - eddp->skb_offset));
+               /* prepare qdio hdr */
+               if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
+@@ -516,20 +516,20 @@
+       
+       QETH_DBF_TEXT(trace, 5, "eddpcanp");
+       /* can we put multiple skbs in one page? */
+-      skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
++      skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len);
+       if (skbs_per_page > 1){
+-              ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
++              ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) /
+                                skbs_per_page + 1;
+               ctx->elements_per_skb = 1;
+       } else {
+               /* no -> how many elements per skb? */
+-              ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
++              ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len +
+                                    PAGE_SIZE) >> PAGE_SHIFT;
+               ctx->num_pages = ctx->elements_per_skb *
+-                               (skb_shinfo(skb)->tso_segs + 1);
++                               (skb_shinfo(skb)->gso_segs + 1);
+       }
+       ctx->num_elements = ctx->elements_per_skb *
+-                          (skb_shinfo(skb)->tso_segs + 1);
++                          (skb_shinfo(skb)->gso_segs + 1);
+ }
+ 
+ static inline struct qeth_eddp_context *
+Index: tmp-xxx/drivers/s390/net/qeth_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_main.c  2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/s390/net/qeth_main.c       2006-11-27 10:52:42.000000000 
+0000
+@@ -4454,7 +4454,7 @@
+       queue = card->qdio.out_qs
+               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+ 
+-      if (skb_shinfo(skb)->tso_size)
++      if (skb_shinfo(skb)->gso_size)
+               large_send = card->options.large_send;
+ 
+       /*are we able to do TSO ? If so ,prepare and send it from here */
+@@ -4501,7 +4501,7 @@
+               card->stats.tx_packets++;
+               card->stats.tx_bytes += skb->len;
+ #ifdef CONFIG_QETH_PERF_STATS
+-              if (skb_shinfo(skb)->tso_size &&
++              if (skb_shinfo(skb)->gso_size &&
+                  !(large_send == QETH_LARGE_SEND_NO)) {
+                       card->perf_stats.large_send_bytes += skb->len;
+                       card->perf_stats.large_send_cnt++;
+Index: tmp-xxx/drivers/s390/net/qeth_tso.h
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_tso.h   2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/drivers/s390/net/qeth_tso.h        2006-11-27 10:52:42.000000000 
+0000
+@@ -51,7 +51,7 @@
+       hdr->ext.hdr_version = 1;
+       hdr->ext.hdr_len     = 28;
+       /*insert non-fix values */
+-      hdr->ext.mss = skb_shinfo(skb)->tso_size;
++      hdr->ext.mss = skb_shinfo(skb)->gso_size;
+       hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
+       hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
+                                      sizeof(struct qeth_hdr_tso));
+Index: tmp-xxx/include/linux/ethtool.h
+===================================================================
+--- tmp-xxx.orig/include/linux/ethtool.h       2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/include/linux/ethtool.h    2006-11-27 10:52:42.000000000 +0000
+@@ -408,6 +408,8 @@
+ #define ETHTOOL_GPERMADDR     0x00000020 /* Get permanent hardware address */
+ #define ETHTOOL_GUFO          0x00000021 /* Get UFO enable (ethtool_value) */
+ #define ETHTOOL_SUFO          0x00000022 /* Set UFO enable (ethtool_value) */
++#define ETHTOOL_GGSO          0x00000023 /* Get GSO enable (ethtool_value) */
++#define ETHTOOL_SGSO          0x00000024 /* Set GSO enable (ethtool_value) */
+ 
+ /* compatibility with older code */
+ #define SPARC_ETH_GSET                ETHTOOL_GSET
+Index: tmp-xxx/include/linux/netdevice.h
+===================================================================
+--- tmp-xxx.orig/include/linux/netdevice.h     2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/include/linux/netdevice.h  2006-11-27 10:52:42.000000000 +0000
+@@ -230,7 +230,8 @@
+       __LINK_STATE_SCHED,
+       __LINK_STATE_NOCARRIER,
+       __LINK_STATE_RX_SCHED,
+-      __LINK_STATE_LINKWATCH_PENDING
++      __LINK_STATE_LINKWATCH_PENDING,
++      __LINK_STATE_QDISC_RUNNING,
+ };
+ 
+ 
+@@ -306,9 +307,17 @@
+ #define NETIF_F_HW_VLAN_RX    256     /* Receive VLAN hw acceleration */
+ #define NETIF_F_HW_VLAN_FILTER        512     /* Receive filtering on VLAN */
+ #define NETIF_F_VLAN_CHALLENGED       1024    /* Device cannot handle VLAN 
packets */
+-#define NETIF_F_TSO           2048    /* Can offload TCP/IP segmentation */
++#define NETIF_F_GSO           2048    /* Enable software GSO. */
+ #define NETIF_F_LLTX          4096    /* LockLess TX */
+-#define NETIF_F_UFO             8192    /* Can offload UDP Large Send*/
++
++      /* Segmentation offload features */
++#define NETIF_F_GSO_SHIFT     16
++#define NETIF_F_TSO           (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
++#define NETIF_F_UFO           (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
++#define NETIF_F_GSO_ROBUST    (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
++
++#define NETIF_F_GEN_CSUM      (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
++#define NETIF_F_ALL_CSUM      (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
+ 
+       struct net_device       *next_sched;
+ 
+@@ -394,6 +403,9 @@
+       struct list_head        qdisc_list;
+       unsigned long           tx_queue_len;   /* Max frames per queue allowed 
*/
+ 
++      /* Partially transmitted GSO packet. */
++      struct sk_buff          *gso_skb;
++
+       /* ingress path synchronizer */
+       spinlock_t              ingress_lock;
+       struct Qdisc            *qdisc_ingress;
+@@ -402,7 +414,7 @@
+  * One part is mostly used on xmit path (device)
+  */
+       /* hard_start_xmit synchronizer */
+-      spinlock_t              xmit_lock ____cacheline_aligned_in_smp;
++      spinlock_t              _xmit_lock ____cacheline_aligned_in_smp;
+       /* cpu id of processor entered to hard_start_xmit or -1,
+          if nobody entered there.
+        */
+@@ -527,6 +539,8 @@
+                                        struct net_device *,
+                                        struct packet_type *,
+                                        struct net_device *);
++      struct sk_buff          *(*gso_segment)(struct sk_buff *skb,
++                                              int features);
+       void                    *af_packet_priv;
+       struct list_head        list;
+ };
+@@ -693,7 +707,8 @@
+ extern int            dev_set_mtu(struct net_device *, int);
+ extern int            dev_set_mac_address(struct net_device *,
+                                           struct sockaddr *);
+-extern void           dev_queue_xmit_nit(struct sk_buff *skb, struct 
net_device *dev);
++extern int            dev_hard_start_xmit(struct sk_buff *skb,
++                                          struct net_device *dev);
+ 
+ extern void           dev_init(void);
+ 
+@@ -900,11 +915,43 @@
+       clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+ }
+ 
++static inline void netif_tx_lock(struct net_device *dev)
++{
++      spin_lock(&dev->_xmit_lock);
++      dev->xmit_lock_owner = smp_processor_id();
++}
++
++static inline void netif_tx_lock_bh(struct net_device *dev)
++{
++      spin_lock_bh(&dev->_xmit_lock);
++      dev->xmit_lock_owner = smp_processor_id();
++}
++
++static inline int netif_tx_trylock(struct net_device *dev)
++{
++      int err = spin_trylock(&dev->_xmit_lock);
++      if (!err)
++              dev->xmit_lock_owner = smp_processor_id();
++      return err;
++}
++
++static inline void netif_tx_unlock(struct net_device *dev)
++{
++      dev->xmit_lock_owner = -1;
++      spin_unlock(&dev->_xmit_lock);
++}
++
++static inline void netif_tx_unlock_bh(struct net_device *dev)
++{
++      dev->xmit_lock_owner = -1;
++      spin_unlock_bh(&dev->_xmit_lock);
++}
++
+ static inline void netif_tx_disable(struct net_device *dev)
+ {
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       netif_stop_queue(dev);
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+ }
+ 
+ /* These functions live elsewhere (drivers/net/net_init.c, but related) */
+@@ -932,6 +979,7 @@
+ extern int            weight_p;
+ extern int            netdev_set_master(struct net_device *dev, struct 
net_device *master);
+ extern int skb_checksum_help(struct sk_buff *skb, int inward);
++extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features);
+ #ifdef CONFIG_BUG
+ extern void netdev_rx_csum_fault(struct net_device *dev);
+ #else
+@@ -951,6 +999,18 @@
+ 
+ extern void linkwatch_run_queue(void);
+ 
++static inline int skb_gso_ok(struct sk_buff *skb, int features)
++{
++      int feature = skb_shinfo(skb)->gso_size ?
++                    skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
++      return (features & feature) == feature;
++}
++
++static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
++{
++      return !skb_gso_ok(skb, dev->features);
++}
++
+ #endif /* __KERNEL__ */
+ 
+ #endif        /* _LINUX_DEV_H */
+Index: tmp-xxx/include/linux/skbuff.h
+===================================================================
+--- tmp-xxx.orig/include/linux/skbuff.h        2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/include/linux/skbuff.h     2006-11-27 10:52:42.000000000 +0000
+@@ -134,9 +134,10 @@
+ struct skb_shared_info {
+       atomic_t        dataref;
+       unsigned short  nr_frags;
+-      unsigned short  tso_size;
+-      unsigned short  tso_segs;
+-      unsigned short  ufo_size;
++      unsigned short  gso_size;
++      /* Warning: this field is not always filled in (UFO)! */
++      unsigned short  gso_segs;
++      unsigned short  gso_type;
+       unsigned int    ip6_frag_id;
+       struct sk_buff  *frag_list;
+       skb_frag_t      frags[MAX_SKB_FRAGS];
+@@ -168,6 +169,14 @@
+       SKB_FCLONE_CLONE,
+ };
+ 
++enum {
++      SKB_GSO_TCPV4 = 1 << 0,
++      SKB_GSO_UDPV4 = 1 << 1,
++
++      /* This indicates the skb is from an untrusted source. */
++      SKB_GSO_DODGY = 1 << 2,
++};
++
+ /** 
+  *    struct sk_buff - socket buffer
+  *    @next: Next buffer in list
+@@ -1148,18 +1157,34 @@
+       return 0;
+ }
+ 
++static inline int __skb_linearize(struct sk_buff *skb)
++{
++      return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM;
++}
++
+ /**
+  *    skb_linearize - convert paged skb to linear one
+  *    @skb: buffer to linarize
+- *    @gfp: allocation mode
+  *
+  *    If there is no free memory -ENOMEM is returned, otherwise zero
+  *    is returned and the old skb data released.
+  */
+-extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp);
+-static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp)
++static inline int skb_linearize(struct sk_buff *skb)
++{
++      return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
++}
++
++/**
++ *    skb_linearize_cow - make sure skb is linear and writable
++ *    @skb: buffer to process
++ *
++ *    If there is no free memory -ENOMEM is returned, otherwise zero
++ *    is returned and the old skb data released.
++ */
++static inline int skb_linearize_cow(struct sk_buff *skb)
+ {
+-      return __skb_linearize(skb, gfp);
++      return skb_is_nonlinear(skb) || skb_cloned(skb) ?
++             __skb_linearize(skb) : 0;
+ }
+ 
+ /**
+@@ -1254,6 +1279,7 @@
+                                struct sk_buff *skb1, const u32 len);
+ 
+ extern void          skb_release_data(struct sk_buff *skb);
++extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
+ 
+ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
+                                      int len, void *buffer)
+Index: tmp-xxx/include/net/pkt_sched.h
+===================================================================
+--- tmp-xxx.orig/include/net/pkt_sched.h       2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/include/net/pkt_sched.h    2006-11-27 10:52:42.000000000 +0000
+@@ -218,12 +218,13 @@
+               struct rtattr *tab);
+ extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
+ 
+-extern int qdisc_restart(struct net_device *dev);
++extern void __qdisc_run(struct net_device *dev);
+ 
+ static inline void qdisc_run(struct net_device *dev)
+ {
+-      while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0)
+-              /* NOTHING */;
++      if (!netif_queue_stopped(dev) &&
++          !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
++              __qdisc_run(dev);
+ }
+ 
+ extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
+Index: tmp-xxx/include/net/protocol.h
+===================================================================
+--- tmp-xxx.orig/include/net/protocol.h        2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/include/net/protocol.h     2006-11-27 10:52:42.000000000 +0000
+@@ -37,6 +37,8 @@
+ struct net_protocol {
+       int                     (*handler)(struct sk_buff *skb);
+       void                    (*err_handler)(struct sk_buff *skb, u32 info);
++      struct sk_buff         *(*gso_segment)(struct sk_buff *skb,
++                                             int features);
+       int                     no_policy;
+ };
+ 
+Index: tmp-xxx/include/net/sock.h
+===================================================================
+--- tmp-xxx.orig/include/net/sock.h    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/sock.h 2006-11-27 10:52:42.000000000 +0000
+@@ -1064,9 +1064,13 @@
+ {
+       __sk_dst_set(sk, dst);
+       sk->sk_route_caps = dst->dev->features;
++      if (sk->sk_route_caps & NETIF_F_GSO)
++              sk->sk_route_caps |= NETIF_F_TSO;
+       if (sk->sk_route_caps & NETIF_F_TSO) {
+               if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
+                       sk->sk_route_caps &= ~NETIF_F_TSO;
++              else 
++                      sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
+       }
+ }
+ 
+Index: tmp-xxx/include/net/tcp.h
+===================================================================
+--- tmp-xxx.orig/include/net/tcp.h     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/tcp.h  2006-11-27 10:52:42.000000000 +0000
+@@ -552,13 +552,13 @@
+  */
+ static inline int tcp_skb_pcount(const struct sk_buff *skb)
+ {
+-      return skb_shinfo(skb)->tso_segs;
++      return skb_shinfo(skb)->gso_segs;
+ }
+ 
+ /* This is valid iff tcp_skb_pcount() > 1. */
+ static inline int tcp_skb_mss(const struct sk_buff *skb)
+ {
+-      return skb_shinfo(skb)->tso_size;
++      return skb_shinfo(skb)->gso_size;
+ }
+ 
+ static inline void tcp_dec_pcount_approx(__u32 *count,
+@@ -1063,6 +1063,8 @@
+ 
+ extern int tcp_v4_destroy_sock(struct sock *sk);
+ 
++extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
++
+ #ifdef CONFIG_PROC_FS
+ extern int  tcp4_proc_init(void);
+ extern void tcp4_proc_exit(void);
+Index: tmp-xxx/net/atm/clip.c
+===================================================================
+--- tmp-xxx.orig/net/atm/clip.c        2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/atm/clip.c     2006-11-27 10:52:42.000000000 +0000
+@@ -101,7 +101,7 @@
+               printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc);
+               return;
+       }
+-      spin_lock_bh(&entry->neigh->dev->xmit_lock);    /* block 
clip_start_xmit() */
++      netif_tx_lock_bh(entry->neigh->dev);    /* block clip_start_xmit() */
+       entry->neigh->used = jiffies;
+       for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
+               if (*walk == clip_vcc) {
+@@ -125,7 +125,7 @@
+       printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
+         "0x%p)\n",entry,clip_vcc);
+ out:
+-      spin_unlock_bh(&entry->neigh->dev->xmit_lock);
++      netif_tx_unlock_bh(entry->neigh->dev);
+ }
+ 
+ /* The neighbour entry n->lock is held. */
+Index: tmp-xxx/net/bridge/br_device.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_device.c        2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/net/bridge/br_device.c     2006-11-27 10:52:42.000000000 +0000
+@@ -146,9 +146,9 @@
+       struct net_bridge *br = netdev_priv(dev);
+ 
+       if (data)
+-              br->feature_mask |= NETIF_F_IP_CSUM;
++              br->feature_mask |= NETIF_F_NO_CSUM;
+       else
+-              br->feature_mask &= ~NETIF_F_IP_CSUM;
++              br->feature_mask &= ~NETIF_F_ALL_CSUM;
+ 
+       br_features_recompute(br);
+       return 0;
+@@ -185,6 +185,6 @@
+       dev->set_mac_address = br_set_mac_address;
+       dev->priv_flags = IFF_EBRIDGE;
+ 
+-      dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
+-              | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM;
++      dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
++                      NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
+ }
+Index: tmp-xxx/net/bridge/br_forward.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_forward.c       2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/net/bridge/br_forward.c    2006-11-27 10:52:42.000000000 +0000
+@@ -32,7 +32,7 @@
+ int br_dev_queue_push_xmit(struct sk_buff *skb)
+ {
+       /* drop mtu oversized packets except tso */
+-      if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
++      if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
+               kfree_skb(skb);
+       else {
+ #ifdef CONFIG_BRIDGE_NETFILTER
+Index: tmp-xxx/net/bridge/br_if.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_if.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/bridge/br_if.c 2006-11-27 10:52:42.000000000 +0000
+@@ -385,17 +385,28 @@
+       struct net_bridge_port *p;
+       unsigned long features, checksum;
+ 
+-      features = br->feature_mask &~ NETIF_F_IP_CSUM;
+-      checksum = br->feature_mask & NETIF_F_IP_CSUM;
++      checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0;
++      features = br->feature_mask & ~NETIF_F_ALL_CSUM;
+ 
+       list_for_each_entry(p, &br->port_list, list) {
+-              if (!(p->dev->features 
+-                    & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)))
++              unsigned long feature = p->dev->features;
++
++              if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
++                      checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
++              if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
++                      checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
++              if (!(feature & NETIF_F_IP_CSUM))
+                       checksum = 0;
+-              features &= p->dev->features;
++
++              if (feature & NETIF_F_GSO)
++                      feature |= NETIF_F_TSO;
++              feature |= NETIF_F_GSO;
++
++              features &= feature;
+       }
+ 
+-      br->dev->features = features | checksum | NETIF_F_LLTX;
++      br->dev->features = features | checksum | NETIF_F_LLTX |
++                          NETIF_F_GSO_ROBUST;
+ }
+ 
+ /* called with RTNL */
+Index: tmp-xxx/net/bridge/br_netfilter.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_netfilter.c     2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/net/bridge/br_netfilter.c  2006-11-27 10:52:42.000000000 +0000
+@@ -743,7 +743,7 @@
+ {
+       if (skb->protocol == htons(ETH_P_IP) &&
+           skb->len > skb->dev->mtu &&
+-          !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
++          !skb_shinfo(skb)->gso_size)
+               return ip_fragment(skb, br_dev_queue_push_xmit);
+       else
+               return br_dev_queue_push_xmit(skb);
+Index: tmp-xxx/net/core/dev.c
+===================================================================
+--- tmp-xxx.orig/net/core/dev.c        2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/dev.c     2006-11-27 10:57:31.000000000 +0000
+@@ -115,6 +115,7 @@
+ #include <net/iw_handler.h>
+ #endif        /* CONFIG_NET_RADIO */
+ #include <asm/current.h>
++#include <linux/err.h>
+ 
+ /*
+  *    The list of packet types we will receive (as opposed to discard)
+@@ -1032,7 +1033,7 @@
+  *    taps currently in use.
+  */
+ 
+-void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
++static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
+ {
+       struct packet_type *ptype;
+ 
+@@ -1106,6 +1107,45 @@
+       return ret;
+ }
+ 
++/**
++ *    skb_gso_segment - Perform segmentation on skb.
++ *    @skb: buffer to segment
++ *    @features: features for the output path (see dev->features)
++ *
++ *    This function segments the given skb and returns a list of segments.
++ *
++ *    It may return NULL if the skb requires no segmentation.  This is
++ *    only possible when GSO is used for verifying header integrity.
++ */
++struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
++{
++      struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
++      struct packet_type *ptype;
++      int type = skb->protocol;
++
++      BUG_ON(skb_shinfo(skb)->frag_list);
++      BUG_ON(skb->ip_summed != CHECKSUM_HW);
++
++      skb->mac.raw = skb->data;
++      skb->mac_len = skb->nh.raw - skb->data;
++      __skb_pull(skb, skb->mac_len);
++
++      rcu_read_lock();
++      list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
++              if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
++                      segs = ptype->gso_segment(skb, features);
++                      break;
++              }
++      }
++      rcu_read_unlock();
++
++      __skb_push(skb, skb->data - skb->mac.raw);
++
++      return segs;
++}
++
++EXPORT_SYMBOL(skb_gso_segment);
++
+ /* Take action when hardware reception checksum errors are detected. */
+ #ifdef CONFIG_BUG
+ void netdev_rx_csum_fault(struct net_device *dev)
+@@ -1142,76 +1182,107 @@
+ #define illegal_highdma(dev, skb)     (0)
+ #endif
+ 
+-/* Keep head the same: replace data */
+-int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
++struct dev_gso_cb {
++      void (*destructor)(struct sk_buff *skb);
++};
++
++#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
++
++static void dev_gso_skb_destructor(struct sk_buff *skb)
+ {
+-      unsigned int size;
+-      u8 *data;
+-      long offset;
+-      struct skb_shared_info *ninfo;
+-      int headerlen = skb->data - skb->head;
+-      int expand = (skb->tail + skb->data_len) - skb->end;
+-
+-      if (skb_shared(skb))
+-              BUG();
+-
+-      if (expand <= 0)
+-              expand = 0;
+-
+-      size = skb->end - skb->head + expand;
+-      size = SKB_DATA_ALIGN(size);
+-      data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+-      if (!data)
+-              return -ENOMEM;
+-
+-      /* Copy entire thing */
+-      if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
+-              BUG();
+-
+-      /* Set up shinfo */
+-      ninfo = (struct skb_shared_info*)(data + size);
+-      atomic_set(&ninfo->dataref, 1);
+-      ninfo->tso_size = skb_shinfo(skb)->tso_size;
+-      ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
+-      ninfo->ufo_size = skb_shinfo(skb)->ufo_size;
+-      ninfo->nr_frags = 0;
+-      ninfo->frag_list = NULL;
+-
+-      /* Offset between the two in bytes */
+-      offset = data - skb->head;
+-
+-      /* Free old data. */
+-      skb_release_data(skb);
+-
+-      skb->head = data;
+-      skb->end  = data + size;
+-
+-      /* Set up new pointers */
+-      skb->h.raw   += offset;
+-      skb->nh.raw  += offset;
+-      skb->mac.raw += offset;
+-      skb->tail    += offset;
+-      skb->data    += offset;
++      struct dev_gso_cb *cb;
+ 
+-      /* We are no longer a clone, even if we were. */
+-      skb->cloned    = 0;
++      do {
++              struct sk_buff *nskb = skb->next;
+ 
+-      skb->tail     += skb->data_len;
+-      skb->data_len  = 0;
++              skb->next = nskb->next;
++              nskb->next = NULL;
++              kfree_skb(nskb);
++      } while (skb->next);
++
++      cb = DEV_GSO_CB(skb);
++      if (cb->destructor)
++              cb->destructor(skb);
++}
++
++/**
++ *    dev_gso_segment - Perform emulated hardware segmentation on skb.
++ *    @skb: buffer to segment
++ *
++ *    This function segments the given skb and stores the list of segments
++ *    in skb->next.
++ */
++static int dev_gso_segment(struct sk_buff *skb)
++{
++      struct net_device *dev = skb->dev;
++      struct sk_buff *segs;
++      int features = dev->features & ~(illegal_highdma(dev, skb) ?
++                                       NETIF_F_SG : 0);
++
++      segs = skb_gso_segment(skb, features);
++
++      /* Verifying header integrity only. */
++      if (!segs)
++              return 0;
++  
++      if (unlikely(IS_ERR(segs)))
++              return PTR_ERR(segs);
++
++      skb->next = segs;
++      DEV_GSO_CB(skb)->destructor = skb->destructor;
++      skb->destructor = dev_gso_skb_destructor;
++      return 0;
++}
++
++int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      if (likely(!skb->next)) {
++              if (netdev_nit)
++                      dev_queue_xmit_nit(skb, dev);
++
++              if (netif_needs_gso(dev, skb)) {
++                      if (unlikely(dev_gso_segment(skb)))
++                              goto out_kfree_skb;
++                      if (skb->next)
++                              goto gso;
++              }
++
++              return dev->hard_start_xmit(skb, dev);
++      }
++
++gso:
++      do {
++              struct sk_buff *nskb = skb->next;
++              int rc;
++
++              skb->next = nskb->next;
++              nskb->next = NULL;
++              rc = dev->hard_start_xmit(nskb, dev);
++              if (unlikely(rc)) {
++                      nskb->next = skb->next;
++                      skb->next = nskb;
++                      return rc;
++              }
++              if (unlikely(netif_queue_stopped(dev) && skb->next))
++                      return NETDEV_TX_BUSY;
++      } while (skb->next);
++      
++      skb->destructor = DEV_GSO_CB(skb)->destructor;
++
++out_kfree_skb:
++      kfree_skb(skb);
+       return 0;
+ }
+ 
+ #define HARD_TX_LOCK(dev, cpu) {                      \
+       if ((dev->features & NETIF_F_LLTX) == 0) {      \
+-              spin_lock(&dev->xmit_lock);             \
+-              dev->xmit_lock_owner = cpu;             \
++              netif_tx_lock(dev);                     \
+       }                                               \
+ }
+ 
+ #define HARD_TX_UNLOCK(dev) {                         \
+       if ((dev->features & NETIF_F_LLTX) == 0) {      \
+-              dev->xmit_lock_owner = -1;              \
+-              spin_unlock(&dev->xmit_lock);           \
++              netif_tx_unlock(dev);                   \
+       }                                               \
+ }
+ 
+@@ -1247,9 +1318,13 @@
+       struct Qdisc *q;
+       int rc = -ENOMEM;
+ 
++      /* GSO will handle the following emulations directly. */
++      if (netif_needs_gso(dev, skb))
++              goto gso;
++
+       if (skb_shinfo(skb)->frag_list &&
+           !(dev->features & NETIF_F_FRAGLIST) &&
+-          __skb_linearize(skb, GFP_ATOMIC))
++          __skb_linearize(skb))
+               goto out_kfree_skb;
+ 
+       /* Fragmented skb is linearized if device does not support SG,
+@@ -1258,25 +1333,26 @@
+        */
+       if (skb_shinfo(skb)->nr_frags &&
+           (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
+-          __skb_linearize(skb, GFP_ATOMIC))
++          __skb_linearize(skb))
+               goto out_kfree_skb;
+ 
+       /* If packet is not checksummed and device does not support
+        * checksumming for this protocol, complete checksumming here.
+        */
+       if (skb->ip_summed == CHECKSUM_HW &&
+-          (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
++          (!(dev->features & NETIF_F_GEN_CSUM) &&
+            (!(dev->features & NETIF_F_IP_CSUM) ||
+             skb->protocol != htons(ETH_P_IP))))
+               if (skb_checksum_help(skb, 0))
+                       goto out_kfree_skb;
+ 
++gso:
+       spin_lock_prefetch(&dev->queue_lock);
+ 
+       /* Disable soft irqs for various locks below. Also 
+        * stops preemption for RCU. 
+        */
+-      local_bh_disable(); 
++      rcu_read_lock_bh(); 
+ 
+       /* Updates of qdisc are serialized by queue_lock. 
+        * The struct Qdisc which is pointed to by qdisc is now a 
+@@ -1310,8 +1386,8 @@
+       /* The device has no queue. Common case for software devices:
+          loopback, all the sorts of tunnels...
+ 
+-         Really, it is unlikely that xmit_lock protection is necessary here.
+-         (f.e. loopback and IP tunnels are clean ignoring statistics
++         Really, it is unlikely that netif_tx_lock protection is necessary
++         here.  (f.e. loopback and IP tunnels are clean ignoring statistics
+          counters.)
+          However, it is possible, that they rely on protection
+          made by us here.
+@@ -1327,11 +1403,8 @@
+                       HARD_TX_LOCK(dev, cpu);
+ 
+                       if (!netif_queue_stopped(dev)) {
+-                              if (netdev_nit)
+-                                      dev_queue_xmit_nit(skb, dev);
+-
+                               rc = 0;
+-                              if (!dev->hard_start_xmit(skb, dev)) {
++                              if (!dev_hard_start_xmit(skb, dev)) {
+                                       HARD_TX_UNLOCK(dev);
+                                       goto out;
+                               }
+@@ -1350,13 +1423,13 @@
+       }
+ 
+       rc = -ENETDOWN;
+-      local_bh_enable();
++      rcu_read_unlock_bh();
+ 
+ out_kfree_skb:
+       kfree_skb(skb);
+       return rc;
+ out:
+-      local_bh_enable();
++      rcu_read_unlock_bh();
+       return rc;
+ }
+ 
+@@ -2671,7 +2744,7 @@
+       BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
+ 
+       spin_lock_init(&dev->queue_lock);
+-      spin_lock_init(&dev->xmit_lock);
++      spin_lock_init(&dev->_xmit_lock);
+       dev->xmit_lock_owner = -1;
+ #ifdef CONFIG_NET_CLS_ACT
+       spin_lock_init(&dev->ingress_lock);
+@@ -2715,9 +2788,7 @@
+ 
+       /* Fix illegal SG+CSUM combinations. */
+       if ((dev->features & NETIF_F_SG) &&
+-          !(dev->features & (NETIF_F_IP_CSUM |
+-                             NETIF_F_NO_CSUM |
+-                             NETIF_F_HW_CSUM))) {
++          !(dev->features & NETIF_F_ALL_CSUM)) {
+               printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
+                      dev->name);
+               dev->features &= ~NETIF_F_SG;
+@@ -3269,7 +3340,6 @@
+ EXPORT_SYMBOL(__dev_get_by_index);
+ EXPORT_SYMBOL(__dev_get_by_name);
+ EXPORT_SYMBOL(__dev_remove_pack);
+-EXPORT_SYMBOL(__skb_linearize);
+ EXPORT_SYMBOL(dev_valid_name);
+ EXPORT_SYMBOL(dev_add_pack);
+ EXPORT_SYMBOL(dev_alloc_name);
+Index: tmp-xxx/net/core/dev_mcast.c
+===================================================================
+--- tmp-xxx.orig/net/core/dev_mcast.c  2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/dev_mcast.c       2006-11-27 10:52:42.000000000 +0000
+@@ -62,7 +62,7 @@
+  *    Device mc lists are changed by bh at least if IPv6 is enabled,
+  *    so that it must be bh protected.
+  *
+- *    We block accesses to device mc filters with dev->xmit_lock.
++ *    We block accesses to device mc filters with netif_tx_lock.
+  */
+ 
+ /*
+@@ -93,9 +93,9 @@
+ 
+ void dev_mc_upload(struct net_device *dev)
+ {
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       __dev_mc_upload(dev);
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+ }
+ 
+ /*
+@@ -107,7 +107,7 @@
+       int err = 0;
+       struct dev_mc_list *dmi, **dmip;
+ 
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+ 
+       for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
+               /*
+@@ -139,13 +139,13 @@
+                        */
+                       __dev_mc_upload(dev);
+                       
+-                      spin_unlock_bh(&dev->xmit_lock);
++                      netif_tx_unlock_bh(dev);
+                       return 0;
+               }
+       }
+       err = -ENOENT;
+ done:
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+       return err;
+ }
+ 
+@@ -160,7 +160,7 @@
+ 
+       dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC);
+ 
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+               if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
+                   dmi->dmi_addrlen == alen) {
+@@ -176,7 +176,7 @@
+       }
+ 
+       if ((dmi = dmi1) == NULL) {
+-              spin_unlock_bh(&dev->xmit_lock);
++              netif_tx_unlock_bh(dev);
+               return -ENOMEM;
+       }
+       memcpy(dmi->dmi_addr, addr, alen);
+@@ -189,11 +189,11 @@
+ 
+       __dev_mc_upload(dev);
+       
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+       return 0;
+ 
+ done:
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+       kfree(dmi1);
+       return err;
+ }
+@@ -204,7 +204,7 @@
+ 
+ void dev_mc_discard(struct net_device *dev)
+ {
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       
+       while (dev->mc_list != NULL) {
+               struct dev_mc_list *tmp = dev->mc_list;
+@@ -215,7 +215,7 @@
+       }
+       dev->mc_count = 0;
+ 
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+ }
+ 
+ #ifdef CONFIG_PROC_FS
+@@ -250,7 +250,7 @@
+       struct dev_mc_list *m;
+       struct net_device *dev = v;
+ 
+-      spin_lock_bh(&dev->xmit_lock);
++      netif_tx_lock_bh(dev);
+       for (m = dev->mc_list; m; m = m->next) {
+               int i;
+ 
+@@ -262,7 +262,7 @@
+ 
+               seq_putc(seq, '\n');
+       }
+-      spin_unlock_bh(&dev->xmit_lock);
++      netif_tx_unlock_bh(dev);
+       return 0;
+ }
+ 
+Index: tmp-xxx/net/core/ethtool.c
+===================================================================
+--- tmp-xxx.orig/net/core/ethtool.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/ethtool.c 2006-11-27 10:52:42.000000000 +0000
+@@ -30,7 +30,7 @@
+ 
+ u32 ethtool_op_get_tx_csum(struct net_device *dev)
+ {
+-      return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
++      return (dev->features & NETIF_F_ALL_CSUM) != 0;
+ }
+ 
+ int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+@@ -551,9 +551,7 @@
+               return -EFAULT;
+ 
+       if (edata.data && 
+-          !(dev->features & (NETIF_F_IP_CSUM |
+-                             NETIF_F_NO_CSUM |
+-                             NETIF_F_HW_CSUM)))
++          !(dev->features & NETIF_F_ALL_CSUM))
+               return -EINVAL;
+ 
+       return __ethtool_set_sg(dev, edata.data);
+@@ -561,7 +559,7 @@
+ 
+ static int ethtool_get_tso(struct net_device *dev, char __user *useraddr)
+ {
+-      struct ethtool_value edata = { ETHTOOL_GTSO };
++      struct ethtool_value edata = { ETHTOOL_GUFO };
+ 
+       if (!dev->ethtool_ops->get_tso)
+               return -EOPNOTSUPP;
+@@ -616,6 +614,29 @@
+       return dev->ethtool_ops->set_ufo(dev, edata.data);
+ }
+ 
++static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
++{
++      struct ethtool_value edata = { ETHTOOL_GGSO };
++
++      edata.data = dev->features & NETIF_F_GSO;
++      if (copy_to_user(useraddr, &edata, sizeof(edata)))
++               return -EFAULT;
++      return 0;
++}
++
++static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
++{
++      struct ethtool_value edata;
++
++      if (copy_from_user(&edata, useraddr, sizeof(edata)))
++              return -EFAULT;
++      if (edata.data)
++              dev->features |= NETIF_F_GSO;
++      else
++              dev->features &= ~NETIF_F_GSO;
++      return 0;
++}
++
+ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
+ {
+       struct ethtool_test test;
+@@ -907,6 +928,12 @@
+       case ETHTOOL_SUFO:
+               rc = ethtool_set_ufo(dev, useraddr);
+               break;
++      case ETHTOOL_GGSO:
++              rc = ethtool_get_gso(dev, useraddr);
++              break;
++      case ETHTOOL_SGSO:
++              rc = ethtool_set_gso(dev, useraddr);
++              break;
+       default:
+               rc =  -EOPNOTSUPP;
+       }
+Index: tmp-xxx/net/core/netpoll.c
+===================================================================
+--- tmp-xxx.orig/net/core/netpoll.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/netpoll.c 2006-11-27 10:52:42.000000000 +0000
+@@ -273,24 +273,21 @@
+ 
+       do {
+               npinfo->tries--;
+-              spin_lock(&np->dev->xmit_lock);
+-              np->dev->xmit_lock_owner = smp_processor_id();
++              netif_tx_lock(np->dev);
+ 
+               /*
+                * network drivers do not expect to be called if the queue is
+                * stopped.
+                */
+               if (netif_queue_stopped(np->dev)) {
+-                      np->dev->xmit_lock_owner = -1;
+-                      spin_unlock(&np->dev->xmit_lock);
++                      netif_tx_unlock(np->dev);
+                       netpoll_poll(np);
+                       udelay(50);
+                       continue;
+               }
+ 
+               status = np->dev->hard_start_xmit(skb, np->dev);
+-              np->dev->xmit_lock_owner = -1;
+-              spin_unlock(&np->dev->xmit_lock);
++              netif_tx_unlock(np->dev);
+ 
+               /* success */
+               if(!status) {
+Index: tmp-xxx/net/core/pktgen.c
+===================================================================
+--- tmp-xxx.orig/net/core/pktgen.c     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/pktgen.c  2006-11-27 10:52:42.000000000 +0000
+@@ -2586,7 +2586,7 @@
+               }
+       }
+       
+-      spin_lock_bh(&odev->xmit_lock);
++      netif_tx_lock_bh(odev);
+       if (!netif_queue_stopped(odev)) {
+ 
+               atomic_inc(&(pkt_dev->skb->users));
+@@ -2631,7 +2631,7 @@
+               pkt_dev->next_tx_ns = 0;
+         }
+ 
+-      spin_unlock_bh(&odev->xmit_lock);
++      netif_tx_unlock_bh(odev);
+       
+       /* If pkt_dev->count is zero, then run forever */
+       if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
+Index: tmp-xxx/net/core/skbuff.c
+===================================================================
+--- tmp-xxx.orig/net/core/skbuff.c     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/skbuff.c  2006-11-27 10:58:31.000000000 +0000
+@@ -164,9 +164,9 @@
+       shinfo = skb_shinfo(skb);
+       atomic_set(&shinfo->dataref, 1);
+       shinfo->nr_frags  = 0;
+-      shinfo->tso_size = 0;
+-      shinfo->tso_segs = 0;
+-      shinfo->ufo_size = 0;
++      shinfo->gso_size = 0;
++      shinfo->gso_segs = 0;
++      shinfo->gso_type = 0;
+       shinfo->ip6_frag_id = 0;
+       shinfo->frag_list = NULL;
+ 
+@@ -230,9 +230,9 @@
+ 
+       atomic_set(&(skb_shinfo(skb)->dataref), 1);
+       skb_shinfo(skb)->nr_frags  = 0;
+-      skb_shinfo(skb)->tso_size = 0;
+-      skb_shinfo(skb)->tso_segs = 0;
+-      skb_shinfo(skb)->ufo_size = 0;
++      skb_shinfo(skb)->gso_size = 0;
++      skb_shinfo(skb)->gso_segs = 0;
++      skb_shinfo(skb)->gso_type = 0;
+       skb_shinfo(skb)->frag_list = NULL;
+ out:
+       return skb;
+@@ -507,9 +507,9 @@
+       new->tc_index   = old->tc_index;
+ #endif
+       atomic_set(&new->users, 1);
+-      skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
+-      skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
+-      skb_shinfo(new)->ufo_size = skb_shinfo(old)->ufo_size;
++      skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
++      skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
++      skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
+ }
+ 
+ /**
+@@ -1822,6 +1822,133 @@
+       return 0;
+ }
+ 
++/**
++ *    skb_segment - Perform protocol segmentation on skb.
++ *    @skb: buffer to segment
++ *    @features: features for the output path (see dev->features)
++ *
++ *    This function performs segmentation on the given skb.  It returns
++ *    the segment at the given position.  It returns NULL if there are
++ *    no more segments to generate, or when an error is encountered.
++ */
++struct sk_buff *skb_segment(struct sk_buff *skb, int features)
++{
++      struct sk_buff *segs = NULL;
++      struct sk_buff *tail = NULL;
++      unsigned int mss = skb_shinfo(skb)->gso_size;
++      unsigned int doffset = skb->data - skb->mac.raw;
++      unsigned int offset = doffset;
++      unsigned int headroom;
++      unsigned int len;
++      int sg = features & NETIF_F_SG;
++      int nfrags = skb_shinfo(skb)->nr_frags;
++      int err = -ENOMEM;
++      int i = 0;
++      int pos;
++
++      __skb_push(skb, doffset);
++      headroom = skb_headroom(skb);
++      pos = skb_headlen(skb);
++
++      do {
++              struct sk_buff *nskb;
++              skb_frag_t *frag;
++              int hsize, nsize;
++              int k;
++              int size;
++
++              len = skb->len - offset;
++              if (len > mss)
++                      len = mss;
++
++              hsize = skb_headlen(skb) - offset;
++              if (hsize < 0)
++                      hsize = 0;
++              nsize = hsize + doffset;
++              if (nsize > len + doffset || !sg)
++                      nsize = len + doffset;
++
++              nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
++              if (unlikely(!nskb))
++                      goto err;
++
++              if (segs)
++                      tail->next = nskb;
++              else
++                      segs = nskb;
++              tail = nskb;
++
++              nskb->dev = skb->dev;
++              nskb->priority = skb->priority;
++              nskb->protocol = skb->protocol;
++              nskb->dst = dst_clone(skb->dst);
++              memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
++              nskb->pkt_type = skb->pkt_type;
++              nskb->mac_len = skb->mac_len;
++
++              skb_reserve(nskb, headroom);
++              nskb->mac.raw = nskb->data;
++              nskb->nh.raw = nskb->data + skb->mac_len;
++              nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
++              memcpy(skb_put(nskb, doffset), skb->data, doffset);
++
++              if (!sg) {
++                      nskb->csum = skb_copy_and_csum_bits(skb, offset,
++                                                          skb_put(nskb, len),
++                                                          len, 0);
++                      continue;
++              }
++
++              frag = skb_shinfo(nskb)->frags;
++              k = 0;
++
++              nskb->ip_summed = CHECKSUM_HW;
++              nskb->csum = skb->csum;
++              memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
++
++              while (pos < offset + len) {
++                      BUG_ON(i >= nfrags);
++
++                      *frag = skb_shinfo(skb)->frags[i];
++                      get_page(frag->page);
++                      size = frag->size;
++
++                      if (pos < offset) {
++                              frag->page_offset += offset - pos;
++                              frag->size -= offset - pos;
++                      }
++
++                      k++;
++
++                      if (pos + size <= offset + len) {
++                              i++;
++                              pos += size;
++                      } else {
++                              frag->size -= pos + size - (offset + len);
++                              break;
++                      }
++
++                      frag++;
++              }
++
++              skb_shinfo(nskb)->nr_frags = k;
++              nskb->data_len = len - hsize;
++              nskb->len += nskb->data_len;
++              nskb->truesize += nskb->data_len;
++      } while ((offset += len) < skb->len);
++
++      return segs;
++
++err:
++      while ((skb = segs)) {
++              segs = skb->next;
++              kfree(skb);
++      }
++      return ERR_PTR(err);
++}
++
++EXPORT_SYMBOL_GPL(skb_segment);
++
+ void __init skb_init(void)
+ {
+       skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
+Index: tmp-xxx/net/decnet/dn_nsp_in.c
+===================================================================
+--- tmp-xxx.orig/net/decnet/dn_nsp_in.c        2006-11-15 10:38:39.000000000 
+0000
++++ tmp-xxx/net/decnet/dn_nsp_in.c     2006-11-27 10:52:42.000000000 +0000
+@@ -801,8 +801,7 @@
+                * We linearize everything except data segments here.
+                */
+               if (cb->nsp_flags & ~0x60) {
+-                      if (unlikely(skb_is_nonlinear(skb)) &&
+-                          skb_linearize(skb, GFP_ATOMIC) != 0)
++                      if (unlikely(skb_linearize(skb)))
+                               goto free_out;
+               }
+ 
+Index: tmp-xxx/net/decnet/dn_route.c
+===================================================================
+--- tmp-xxx.orig/net/decnet/dn_route.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/decnet/dn_route.c      2006-11-27 10:52:42.000000000 +0000
+@@ -629,8 +629,7 @@
+                       padlen);
+ 
+         if (flags & DN_RT_PKT_CNTL) {
+-              if (unlikely(skb_is_nonlinear(skb)) &&
+-                  skb_linearize(skb, GFP_ATOMIC) != 0)
++              if (unlikely(skb_linearize(skb)))
+                       goto dump_it;
+ 
+                 switch(flags & DN_RT_CNTL_MSK) {
+Index: tmp-xxx/net/ipv4/af_inet.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/af_inet.c    2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/af_inet.c 2006-11-27 10:52:42.000000000 +0000
+@@ -68,6 +68,7 @@
+  */
+ 
+ #include <linux/config.h>
++#include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/types.h>
+ #include <linux/socket.h>
+@@ -1084,6 +1085,54 @@
+ 
+ EXPORT_SYMBOL(inet_sk_rebuild_header);
+ 
++static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
++{
++      struct sk_buff *segs = ERR_PTR(-EINVAL);
++      struct iphdr *iph;
++      struct net_protocol *ops;
++      int proto;
++      int ihl;
++      int id;
++
++      if (!pskb_may_pull(skb, sizeof(*iph)))
++              goto out;
++
++      iph = skb->nh.iph;
++      ihl = iph->ihl * 4;
++      if (ihl < sizeof(*iph))
++              goto out;
++
++      if (!pskb_may_pull(skb, ihl))
++              goto out;
++
++      skb->h.raw = __skb_pull(skb, ihl);
++      iph = skb->nh.iph;
++      id = ntohs(iph->id);
++      proto = iph->protocol & (MAX_INET_PROTOS - 1);
++      segs = ERR_PTR(-EPROTONOSUPPORT);
++
++      rcu_read_lock();
++      ops = rcu_dereference(inet_protos[proto]);
++      if (ops && ops->gso_segment)
++              segs = ops->gso_segment(skb, features);
++      rcu_read_unlock();
++
++      if (!segs || unlikely(IS_ERR(segs)))
++              goto out;
++
++      skb = segs;
++      do {
++              iph = skb->nh.iph;
++              iph->id = htons(id++);
++              iph->tot_len = htons(skb->len - skb->mac_len);
++              iph->check = 0;
++              iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
++      } while ((skb = skb->next));
++
++out:
++      return segs;
++}
++
+ #ifdef CONFIG_IP_MULTICAST
+ static struct net_protocol igmp_protocol = {
+       .handler =      igmp_rcv,
+@@ -1093,6 +1142,7 @@
+ static struct net_protocol tcp_protocol = {
+       .handler =      tcp_v4_rcv,
+       .err_handler =  tcp_v4_err,
++      .gso_segment =  tcp_tso_segment,
+       .no_policy =    1,
+ };
+ 
+@@ -1138,6 +1188,7 @@
+ static struct packet_type ip_packet_type = {
+       .type = __constant_htons(ETH_P_IP),
+       .func = ip_rcv,
++      .gso_segment = inet_gso_segment,
+ };
+ 
+ static int __init inet_init(void)
+Index: tmp-xxx/net/ipv4/ip_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/ip_output.c  2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/ip_output.c       2006-11-27 10:52:42.000000000 +0000
+@@ -210,8 +210,7 @@
+               return dst_output(skb);
+       }
+ #endif
+-      if (skb->len > dst_mtu(skb->dst) &&
+-          !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
++      if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
+               return ip_fragment(skb, ip_finish_output2);
+       else
+               return ip_finish_output2(skb);
+@@ -362,7 +361,7 @@
+       }
+ 
+       ip_select_ident_more(iph, &rt->u.dst, sk,
+-                           (skb_shinfo(skb)->tso_segs ?: 1) - 1);
++                           (skb_shinfo(skb)->gso_segs ?: 1) - 1);
+ 
+       /* Add an IP checksum. */
+       ip_send_check(iph);
+@@ -743,7 +742,8 @@
+                              (length - transhdrlen));
+       if (!err) {
+               /* specify the length of each IP datagram fragment*/
+-              skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
++              skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
++              skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
+               __skb_queue_tail(&sk->sk_write_queue, skb);
+ 
+               return 0;
+@@ -839,7 +839,7 @@
+        */
+       if (transhdrlen &&
+           length + fragheaderlen <= mtu &&
+-          
rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) &&
++          rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
+           !exthdrlen)
+               csummode = CHECKSUM_HW;
+ 
+@@ -1086,14 +1086,16 @@
+ 
+       inet->cork.length += size;
+       if ((sk->sk_protocol == IPPROTO_UDP) &&
+-          (rt->u.dst.dev->features & NETIF_F_UFO))
+-              skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
++          (rt->u.dst.dev->features & NETIF_F_UFO)) {
++              skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
++              skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
++      }
+ 
+ 
+       while (size > 0) {
+               int i;
+ 
+-              if (skb_shinfo(skb)->ufo_size)
++              if (skb_shinfo(skb)->gso_size)
+                       len = size;
+               else {
+ 
+Index: tmp-xxx/net/ipv4/ipcomp.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/ipcomp.c     2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/ipcomp.c  2006-11-27 10:52:42.000000000 +0000
+@@ -84,7 +84,7 @@
+                         struct xfrm_decap_state *decap, struct sk_buff *skb)
+ {
+       u8 nexthdr;
+-      int err = 0;
++      int err = -ENOMEM;
+       struct iphdr *iph;
+       union {
+               struct iphdr    iph;
+@@ -92,11 +92,8 @@
+       } tmp_iph;
+ 
+ 
+-      if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+-          skb_linearize(skb, GFP_ATOMIC) != 0) {
+-              err = -ENOMEM;
++      if (skb_linearize_cow(skb))
+               goto out;
+-      }
+ 
+       skb->ip_summed = CHECKSUM_NONE;
+ 
+@@ -171,10 +168,8 @@
+               goto out_ok;
+       }
+ 
+-      if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+-          skb_linearize(skb, GFP_ATOMIC) != 0) {
++      if (skb_linearize_cow(skb))
+               goto out_ok;
+-      }
+       
+       err = ipcomp_compress(x, skb);
+       iph = skb->nh.iph;
+Index: tmp-xxx/net/ipv4/tcp.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp.c        2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp.c     2006-11-27 10:52:42.000000000 +0000
+@@ -257,6 +257,7 @@
+ #include <linux/fs.h>
+ #include <linux/random.h>
+ #include <linux/bootmem.h>
++#include <linux/err.h>
+ 
+ #include <net/icmp.h>
+ #include <net/tcp.h>
+@@ -570,7 +571,7 @@
+               skb->ip_summed = CHECKSUM_HW;
+               tp->write_seq += copy;
+               TCP_SKB_CB(skb)->end_seq += copy;
+-              skb_shinfo(skb)->tso_segs = 0;
++              skb_shinfo(skb)->gso_segs = 0;
+ 
+               if (!copied)
+                       TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+@@ -621,14 +622,10 @@
+       ssize_t res;
+       struct sock *sk = sock->sk;
+ 
+-#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | 
NETIF_F_HW_CSUM)
+-
+       if (!(sk->sk_route_caps & NETIF_F_SG) ||
+-          !(sk->sk_route_caps & TCP_ZC_CSUM_FLAGS))
++          !(sk->sk_route_caps & NETIF_F_ALL_CSUM))
+               return sock_no_sendpage(sock, page, offset, size, flags);
+ 
+-#undef TCP_ZC_CSUM_FLAGS
+-
+       lock_sock(sk);
+       TCP_CHECK_TIMER(sk);
+       res = do_tcp_sendpages(sk, &page, offset, size, flags);
+@@ -725,9 +722,7 @@
+                               /*
+                                * Check whether we can use HW checksum.
+                                */
+-                              if (sk->sk_route_caps &
+-                                  (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM |
+-                                   NETIF_F_HW_CSUM))
++                              if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
+                                       skb->ip_summed = CHECKSUM_HW;
+ 
+                               skb_entail(sk, tp, skb);
+@@ -823,7 +818,7 @@
+ 
+                       tp->write_seq += copy;
+                       TCP_SKB_CB(skb)->end_seq += copy;
+-                      skb_shinfo(skb)->tso_segs = 0;
++                      skb_shinfo(skb)->gso_segs = 0;
+ 
+                       from += copy;
+                       copied += copy;
+@@ -2026,6 +2021,71 @@
+ }
+ 
+ 
++struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
++{
++      struct sk_buff *segs = ERR_PTR(-EINVAL);
++      struct tcphdr *th;
++      unsigned thlen;
++      unsigned int seq;
++      unsigned int delta;
++      unsigned int oldlen;
++      unsigned int len;
++
++      if (!pskb_may_pull(skb, sizeof(*th)))
++              goto out;
++
++      th = skb->h.th;
++      thlen = th->doff * 4;
++      if (thlen < sizeof(*th))
++              goto out;
++
++      if (!pskb_may_pull(skb, thlen))
++              goto out;
++
++      segs = NULL;
++      if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST))
++              goto out;
++
++      oldlen = (u16)~skb->len;
++      __skb_pull(skb, thlen);
++
++      segs = skb_segment(skb, features);
++      if (IS_ERR(segs))
++              goto out;
++
++      len = skb_shinfo(skb)->gso_size;
++      delta = htonl(oldlen + (thlen + len));
++
++      skb = segs;
++      th = skb->h.th;
++      seq = ntohl(th->seq);
++
++      do {
++              th->fin = th->psh = 0;
++
++              th->check = ~csum_fold(th->check + delta);
++              if (skb->ip_summed != CHECKSUM_HW)
++                      th->check = csum_fold(csum_partial(skb->h.raw, thlen,
++                                                         skb->csum));
++
++              seq += len;
++              skb = skb->next;
++              th = skb->h.th;
++
++              th->seq = htonl(seq);
++              th->cwr = 0;
++      } while (skb->next);
++
++      delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
++      th->check = ~csum_fold(th->check + delta);
++      if (skb->ip_summed != CHECKSUM_HW)
++              th->check = csum_fold(csum_partial(skb->h.raw, thlen,
++                                                 skb->csum));
++
++out:
++      return segs;
++}
++
+ extern void __skb_cb_too_small_for_tcp(int, int);
+ extern struct tcp_congestion_ops tcp_reno;
+ 
+Index: tmp-xxx/net/ipv4/tcp_input.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp_input.c  2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp_input.c       2006-11-27 10:52:42.000000000 +0000
+@@ -1072,7 +1072,7 @@
+                               else
+                                       pkt_len = (end_seq -
+                                                  TCP_SKB_CB(skb)->seq);
+-                              if (tcp_fragment(sk, skb, pkt_len, 
skb_shinfo(skb)->tso_size))
++                              if (tcp_fragment(sk, skb, pkt_len, 
skb_shinfo(skb)->gso_size))
+                                       break;
+                               pcount = tcp_skb_pcount(skb);
+                       }
+Index: tmp-xxx/net/ipv4/tcp_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp_output.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp_output.c      2006-11-27 10:52:42.000000000 +0000
+@@ -497,15 +497,17 @@
+               /* Avoid the costly divide in the normal
+                * non-TSO case.
+                */
+-              skb_shinfo(skb)->tso_segs = 1;
+-              skb_shinfo(skb)->tso_size = 0;
++              skb_shinfo(skb)->gso_segs = 1;
++              skb_shinfo(skb)->gso_size = 0;
++              skb_shinfo(skb)->gso_type = 0;
+       } else {
+               unsigned int factor;
+ 
+               factor = skb->len + (mss_now - 1);
+               factor /= mss_now;
+-              skb_shinfo(skb)->tso_segs = factor;
+-              skb_shinfo(skb)->tso_size = mss_now;
++              skb_shinfo(skb)->gso_segs = factor;
++              skb_shinfo(skb)->gso_size = mss_now;
++              skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+       }
+ }
+ 
+@@ -850