# HG changeset patch
# User Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
# Node ID 041be3f6b38e05f904d240630c18cadb1259317b
# Parent c5d4d47bbeb8a489a2160174c08a04aaebef3d6f
[linux patches] Update patches for linux-2.6.16.29.
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
---
patches/linux-2.6.16.13/blktap-aio-16_03_06.patch
| 274 -
patches/linux-2.6.16.13/device_bind.patch
| 14
patches/linux-2.6.16.13/fix-hz-suspend.patch
| 25
patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch
| 13
patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch
| 35
patches/linux-2.6.16.13/ipv6-no-autoconf.patch
| 22
patches/linux-2.6.16.13/net-csum.patch
| 57
patches/linux-2.6.16.13/net-gso-0-base.patch
| 2510 ----------
patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch
| 22
patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch
| 400 -
patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch
| 13
patches/linux-2.6.16.13/net-gso-4-kill-warnon.patch
| 18
patches/linux-2.6.16.13/pmd-shared.patch
| 100
patches/linux-2.6.16.13/rcu_needs_cpu.patch
| 31
patches/linux-2.6.16.13/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
| 26
patches/linux-2.6.16.13/series
| 23
patches/linux-2.6.16.13/smp-alts.patch
| 540 --
patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch
| 1381 -----
patches/linux-2.6.16.13/x86-elfnote-as-preprocessor-macro.patch
| 28
patches/linux-2.6.16.13/x86-increase-interrupt-vector-range.patch
| 73
patches/linux-2.6.16.13/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
| 168
patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
| 71
patches/linux-2.6.16.13/xen-hotplug.patch
| 9
patches/linux-2.6.16.13/xenoprof-generic.patch
| 568 --
patches/linux-2.6.16.29/blktap-aio-16_03_06.patch
| 161
patches/linux-2.6.16.29/device_bind.patch
| 9
patches/linux-2.6.16.29/fix-hz-suspend.patch
| 9
patches/linux-2.6.16.29/fix-ide-cd-pio-mode.patch
| 13
patches/linux-2.6.16.29/i386-mach-io-check-nmi.patch
| 30
patches/linux-2.6.16.29/ipv6-no-autoconf.patch
| 16
patches/linux-2.6.16.29/net-csum.patch
| 40
patches/linux-2.6.16.29/net-gso-0-base.patch
| 1906 +++++++
patches/linux-2.6.16.29/net-gso-1-check-dodgy.patch
| 16
patches/linux-2.6.16.29/net-gso-2-checksum-fix.patch
| 311 +
patches/linux-2.6.16.29/net-gso-3-fix-errorcheck.patch
| 13
patches/linux-2.6.16.29/net-gso-4-kill-warnon.patch
| 26
patches/linux-2.6.16.29/pmd-shared.patch
| 57
patches/linux-2.6.16.29/rcu_needs_cpu.patch
| 18
patches/linux-2.6.16.29/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
| 26
patches/linux-2.6.16.29/series
| 23
patches/linux-2.6.16.29/smp-alts.patch
| 330 +
patches/linux-2.6.16.29/tpm_plugin_2.6.17.patch
| 703 ++
patches/linux-2.6.16.29/x86-elfnote-as-preprocessor-macro.patch
| 25
patches/linux-2.6.16.29/x86-increase-interrupt-vector-range.patch
| 73
patches/linux-2.6.16.29/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
| 39
patches/linux-2.6.16.29/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
| 63
patches/linux-2.6.16.29/xen-hotplug.patch
| 10
patches/linux-2.6.16.29/xenoprof-generic.patch
| 268 +
48 files changed, 4185 insertions(+), 6421 deletions(-)
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/blktap-aio-16_03_06.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/blktap-aio-16_03_06.patch Tue Sep 19 14:26:47
2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/device_bind.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/device_bind.patch Tue Sep 19 14:26:47 2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/fix-hz-suspend.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/fix-hz-suspend.patch Tue Sep 19 14:26:47
2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/fix-ide-cd-pio-mode.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/fix-ide-cd-pio-mode.patch Tue Sep 19 14:26:47
2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/i386-mach-io-check-nmi.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/i386-mach-io-check-nmi.patch Tue Sep 19
14:26:47 2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/ipv6-no-autoconf.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/ipv6-no-autoconf.patch Tue Sep 19 14:26:47
2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/net-csum.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-csum.patch Tue Sep 19 14:26:47 2006 +0100
@@ -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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/net-gso-0-base.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-gso-0-base.patch Tue Sep 19 14:26:47
2006 +0100
@@ -0,0 +1,2835 @@
+diff -pruN ../orig-linux-2.6.16.29/Documentation/networking/netdevices.txt
./Documentation/networking/netdevices.txt
+--- ../orig-linux-2.6.16.29/Documentation/networking/netdevices.txt
2006-09-12 19:02:10.000000000 +0100
++++ ./Documentation/networking/netdevices.txt 2006-09-19 13:59:20.000000000
+0100
+@@ -42,9 +42,9 @@ dev->get_stats:
+ 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 @@ dev->hard_start_xmit:
+ 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:
+diff -pruN ../orig-linux-2.6.16.29/drivers/block/aoe/aoenet.c
./drivers/block/aoe/aoenet.c
+--- ../orig-linux-2.6.16.29/drivers/block/aoe/aoenet.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/block/aoe/aoenet.c 2006-09-19 13:59:20.000000000 +0100
+@@ -95,9 +95,8 @@ mac_addr(char addr[6])
+ 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;
+ }
+diff -pruN
../orig-linux-2.6.16.29/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
./drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+--- ../orig-linux-2.6.16.29/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/infiniband/ulp/ipoib/ipoib_multicast.c 2006-09-19
13:59:20.000000000 +0100
+@@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_
+
+ 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 @@ void ipoib_mcast_restart_task(void *dev_
+ }
+
+ 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) {
+diff -pruN ../orig-linux-2.6.16.29/drivers/media/dvb/dvb-core/dvb_net.c
./drivers/media/dvb/dvb-core/dvb_net.c
+--- ../orig-linux-2.6.16.29/drivers/media/dvb/dvb-core/dvb_net.c
2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/media/dvb/dvb-core/dvb_net.c 2006-09-19 13:59:20.000000000
+0100
+@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void
+
+ 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);
+@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void
+ }
+ }
+
+- spin_unlock_bh(&dev->xmit_lock);
++ netif_tx_unlock_bh(dev);
+ dvb_net_feed_start(dev);
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/8139cp.c ./drivers/net/8139cp.c
+--- ../orig-linux-2.6.16.29/drivers/net/8139cp.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/8139cp.c 2006-09-19 13:59:20.000000000 +0100
+@@ -794,7 +794,7 @@ static int cp_start_xmit (struct sk_buff
+ 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];
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/bnx2.c ./drivers/net/bnx2.c
+--- ../orig-linux-2.6.16.29/drivers/net/bnx2.c 2006-09-12 19:02:10.000000000
+0100
++++ ./drivers/net/bnx2.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
+ 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 @@ bnx2_poll(struct net_device *dev, int *b
+ 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 @@ bnx2_vlan_rx_kill_vid(struct net_device
+ }
+ #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 @@ bnx2_start_xmit(struct sk_buff *skb, str
+ (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;
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/bonding/bond_main.c
./drivers/net/bonding/bond_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/bonding/bond_main.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/bonding/bond_main.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1145,8 +1145,7 @@ int bond_sethwaddr(struct net_device *bo
+ }
+
+ #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 @@ static int bond_compute_features(struct
+ 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 @@ static int bond_init(struct net_device *
+ */
+ 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;
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c
./drivers/net/chelsio/sge.c
+--- ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/chelsio/sge.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
+ 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 @@ int t1_start_xmit(struct sk_buff *skb, s
+ 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++;
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c
./drivers/net/e1000/e1000_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/e1000/e1000_main.c 2006-09-19 13:59:20.000000000 +0100
+@@ -2526,7 +2526,7 @@ e1000_tso(struct e1000_adapter *adapter,
+ 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 @@ e1000_tso(struct e1000_adapter *adapter,
+ }
+
+ 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 @@ e1000_tx_map(struct e1000_adapter *adapt
+ * 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 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ }
+
+ #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 @@ e1000_xmit_frame(struct sk_buff *skb, st
+ #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
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/forcedeth.c
./drivers/net/forcedeth.c
+--- ../orig-linux-2.6.16.29/drivers/net/forcedeth.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/forcedeth.c 2006-09-19 13:59:20.000000000 +0100
+@@ -482,9 +482,9 @@ typedef union _ring_type {
+ * 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 @@ static void drain_ring(struct net_device
+
+ /*
+ * 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 @@ static int nv_start_xmit(struct sk_buff
+ 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 @@ static void nv_tx_done(struct net_device
+
+ /*
+ * 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 @@ static int nv_change_mtu(struct net_devi
+ * 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 @@ static int nv_change_mtu(struct net_devi
+ 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 @@ static int nv_set_mac_address(struct net
+ 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 @@ static int nv_set_mac_address(struct net
+ /* 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 @@ static int nv_set_mac_address(struct net
+
+ /*
+ * 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)
+ {
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/hamradio/6pack.c
./drivers/net/hamradio/6pack.c
+--- ../orig-linux-2.6.16.29/drivers/net/hamradio/6pack.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/hamradio/6pack.c 2006-09-19 13:59:20.000000000 +0100
+@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net
+ {
+ 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 @@ static int sixpack_ioctl(struct tty_stru
+ 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;
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/hamradio/mkiss.c
./drivers/net/hamradio/mkiss.c
+--- ../orig-linux-2.6.16.29/drivers/net/hamradio/mkiss.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/hamradio/mkiss.c 2006-09-19 13:59:20.000000000 +0100
+@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net
+ {
+ 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 @@ static int mkiss_ioctl(struct tty_struct
+ 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;
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/ifb.c ./drivers/net/ifb.c
+--- ../orig-linux-2.6.16.29/drivers/net/ifb.c 2006-09-12 19:02:10.000000000
+0100
++++ ./drivers/net/ifb.c 2006-09-19 13:59:20.000000000 +0100
+@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev
+ 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 @@ static void ri_tasklet(unsigned long dev
+ }
+ }
+
+- 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 @@ static void ri_tasklet(unsigned long dev
+ 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;
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/irda/vlsi_ir.c
./drivers/net/irda/vlsi_ir.c
+--- ../orig-linux-2.6.16.29/drivers/net/irda/vlsi_ir.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/irda/vlsi_ir.c 2006-09-19 13:59:20.000000000 +0100
+@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct s
+ || (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! */
+ }
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c
./drivers/net/ixgb/ixgb_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/ixgb/ixgb_main.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1163,7 +1163,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+ 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 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+ }
+
+ 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,
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/loopback.c
./drivers/net/loopback.c
+--- ../orig-linux-2.6.16.29/drivers/net/loopback.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/loopback.c 2006-09-19 13:59:20.000000000 +0100
+@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
+ 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 @@ static int loopback_xmit(struct sk_buff
+ #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);
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/mv643xx_eth.c
./drivers/net/mv643xx_eth.c
+--- ../orig-linux-2.6.16.29/drivers/net/mv643xx_eth.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/mv643xx_eth.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1107,7 +1107,7 @@ static int mv643xx_eth_start_xmit(struct
+
+ #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);
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/natsemi.c
./drivers/net/natsemi.c
+--- ../orig-linux-2.6.16.29/drivers/net/natsemi.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/natsemi.c 2006-09-19 13:59:20.000000000 +0100
+@@ -323,12 +323,12 @@ performance critical codepaths:
+ 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
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/r8169.c ./drivers/net/r8169.c
+--- ../orig-linux-2.6.16.29/drivers/net/r8169.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/r8169.c 2006-09-19 13:59:20.000000000 +0100
+@@ -2171,7 +2171,7 @@ static int rtl8169_xmit_frags(struct rtl
+ 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);
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/s2io.c ./drivers/net/s2io.c
+--- ../orig-linux-2.6.16.29/drivers/net/s2io.c 2006-09-12 19:02:10.000000000
+0100
++++ ./drivers/net/s2io.c 2006-09-19 13:59:20.000000000 +0100
+@@ -3522,8 +3522,8 @@ static int s2io_xmit(struct sk_buff *skb
+ 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 @@ static int s2io_xmit(struct sk_buff *skb
+ }
+
+ 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 @@ static int s2io_xmit(struct sk_buff *skb
+ 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 @@ static int s2io_xmit(struct sk_buff *skb
+ (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 @@ static int s2io_xmit(struct sk_buff *skb
+ 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);
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/sky2.c ./drivers/net/sky2.c
+--- ../orig-linux-2.6.16.29/drivers/net/sky2.c 2006-09-12 19:02:10.000000000
+0100
++++ ./drivers/net/sky2.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
+ 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)
+@@ -1197,7 +1197,7 @@ static int sky2_xmit_frame(struct sk_buf
+ }
+
+ /* 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) &&
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/tg3.c ./drivers/net/tg3.c
+--- ../orig-linux-2.6.16.29/drivers/net/tg3.c 2006-09-12 19:02:10.000000000
+0100
++++ ./drivers/net/tg3.c 2006-09-19 13:59:20.000000000 +0100
+@@ -3664,7 +3664,7 @@ static int tg3_start_xmit(struct sk_buff
+ #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) &&
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/tulip/winbond-840.c
./drivers/net/tulip/winbond-840.c
+--- ../orig-linux-2.6.16.29/drivers/net/tulip/winbond-840.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/tulip/winbond-840.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1605,11 +1605,11 @@ static void __devexit w840_remove1 (stru
+ * - 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 @@ static int w840_suspend (struct pci_dev
+ 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;
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/typhoon.c
./drivers/net/typhoon.c
+--- ../orig-linux-2.6.16.29/drivers/net/typhoon.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/typhoon.c 2006-09-19 13:59:20.000000000 +0100
+@@ -340,7 +340,7 @@ enum state_values {
+ #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
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/via-velocity.c
./drivers/net/via-velocity.c
+--- ../orig-linux-2.6.16.29/drivers/net/via-velocity.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/via-velocity.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff
+
+ 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];
+@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff
+ */
+ 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);
+@@ -1933,7 +1938,6 @@ static int velocity_xmit(struct sk_buff
+ 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 =
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/wireless/orinoco.c
./drivers/net/wireless/orinoco.c
+--- ../orig-linux-2.6.16.29/drivers/net/wireless/orinoco.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/net/wireless/orinoco.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1835,7 +1835,9 @@ static int __orinoco_program_rids(struct
+ /* 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;
+ }
+diff -pruN ../orig-linux-2.6.16.29/drivers/s390/net/qeth_eddp.c
./drivers/s390/net/qeth_eddp.c
+--- ../orig-linux-2.6.16.29/drivers/s390/net/qeth_eddp.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/s390/net/qeth_eddp.c 2006-09-19 13:59:20.000000000 +0100
+@@ -421,7 +421,7 @@ __qeth_eddp_fill_context_tcp(struct qeth
+ }
+ 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_eddp_calc_num_pages(struct qeth_edd
+
+ 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 *
+diff -pruN ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c
./drivers/s390/net/qeth_main.c
+--- ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/s390/net/qeth_main.c 2006-09-19 13:59:20.000000000 +0100
+@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
+ 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 @@ qeth_send_packet(struct qeth_card *card,
+ 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++;
+diff -pruN ../orig-linux-2.6.16.29/drivers/s390/net/qeth_tso.h
./drivers/s390/net/qeth_tso.h
+--- ../orig-linux-2.6.16.29/drivers/s390/net/qeth_tso.h 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/s390/net/qeth_tso.h 2006-09-19 13:59:20.000000000 +0100
+@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
+ 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));
+diff -pruN ../orig-linux-2.6.16.29/include/linux/ethtool.h
./include/linux/ethtool.h
+--- ../orig-linux-2.6.16.29/include/linux/ethtool.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/linux/ethtool.h 2006-09-19 13:59:20.000000000 +0100
+@@ -408,6 +408,8 @@ struct ethtool_ops {
+ #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
+diff -pruN ../orig-linux-2.6.16.29/include/linux/netdevice.h
./include/linux/netdevice.h
+--- ../orig-linux-2.6.16.29/include/linux/netdevice.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/linux/netdevice.h 2006-09-19 13:59:20.000000000 +0100
+@@ -230,7 +230,8 @@ enum netdev_state_t
+ __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 @@ struct net_device
+ #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 net_device
+ 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 @@ struct net_device
+ * 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 packet_type {
+ 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_change_name(struct net_d
+ 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 @@ static inline void __netif_rx_complete(s
+ 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 netdev_max_backlog;
+ 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 dev_seq_stop(struct seq_file
+
+ 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 */
+diff -pruN ../orig-linux-2.6.16.29/include/linux/skbuff.h
./include/linux/skbuff.h
+--- ../orig-linux-2.6.16.29/include/linux/skbuff.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/linux/skbuff.h 2006-09-19 13:59:20.000000000 +0100
+@@ -134,9 +134,10 @@ struct skb_frag_struct {
+ 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 @@ enum {
+ 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 @@ static inline int skb_can_coalesce(struc
+ 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 @@ extern void skb_split(struct sk_b
+ 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)
+diff -pruN ../orig-linux-2.6.16.29/include/net/pkt_sched.h
./include/net/pkt_sched.h
+--- ../orig-linux-2.6.16.29/include/net/pkt_sched.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/net/pkt_sched.h 2006-09-19 13:59:20.000000000 +0100
+@@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_ge
+ 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,
+diff -pruN ../orig-linux-2.6.16.29/include/net/protocol.h
./include/net/protocol.h
+--- ../orig-linux-2.6.16.29/include/net/protocol.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/net/protocol.h 2006-09-19 13:59:20.000000000 +0100
+@@ -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;
+ };
+
+diff -pruN ../orig-linux-2.6.16.29/include/net/sock.h ./include/net/sock.h
+--- ../orig-linux-2.6.16.29/include/net/sock.h 2006-09-12 19:02:10.000000000
+0100
++++ ./include/net/sock.h 2006-09-19 13:59:20.000000000 +0100
+@@ -1064,9 +1064,13 @@ static inline void sk_setup_caps(struct
+ {
+ __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;
+ }
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/include/net/tcp.h ./include/net/tcp.h
+--- ../orig-linux-2.6.16.29/include/net/tcp.h 2006-09-12 19:02:10.000000000
+0100
++++ ./include/net/tcp.h 2006-09-19 13:59:20.000000000 +0100
+@@ -552,13 +552,13 @@ struct tcp_skb_cb {
+ */
+ 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 struct request_sock_ops tcp_reque
+
+ 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);
+diff -pruN ../orig-linux-2.6.16.29/net/atm/clip.c ./net/atm/clip.c
+--- ../orig-linux-2.6.16.29/net/atm/clip.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/atm/clip.c 2006-09-19 13:59:20.000000000 +0100
+@@ -101,7 +101,7 @@ static void unlink_clip_vcc(struct clip_
+ 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 @@ static void unlink_clip_vcc(struct clip_
+ 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. */
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_device.c
./net/bridge/br_device.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_device.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/bridge/br_device.c 2006-09-19 13:59:20.000000000 +0100
+@@ -146,9 +146,9 @@ static int br_set_tx_csum(struct net_dev
+ 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 @@ void br_dev_setup(struct net_device *dev
+ 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;
+ }
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_forward.c
./net/bridge/br_forward.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_forward.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/bridge/br_forward.c 2006-09-19 13:59:20.000000000 +0100
+@@ -32,7 +32,7 @@ static inline int should_deliver(const s
+ 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
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_if.c ./net/bridge/br_if.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_if.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/bridge/br_if.c 2006-09-19 13:59:20.000000000 +0100
+@@ -385,17 +385,28 @@ void br_features_recompute(struct net_br
+ 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 */
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c
./net/bridge/br_netfilter.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/bridge/br_netfilter.c 2006-09-19 13:59:20.000000000 +0100
+@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
+ {
+ 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);
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.16.29/net/core/dev.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/core/dev.c 2006-09-19 13:59:20.000000000 +0100
+@@ -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 @@ static inline void net_timestamp(struct
+ * 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 @@ out:
+ 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,75 +1182,108 @@ static inline int illegal_highdma(struct
+ #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)
++{
++ struct dev_gso_cb *cb;
++
++ do {
++ struct sk_buff *nskb = skb->next;
++
++ 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)
+ {
+- 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->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 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;
+
+- /* We are no longer a clone, even if we were. */
+- skb->cloned = 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;
+
+- skb->tail += skb->data_len;
+- skb->data_len = 0;
++ 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); \
+ } \
+ }
+
+@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
+ 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,
+@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
+ */
+ 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
+@@ -1309,8 +1387,8 @@ int dev_queue_xmit(struct sk_buff *skb)
+ /* 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.
+@@ -1326,11 +1404,8 @@ int dev_queue_xmit(struct sk_buff *skb)
+ 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;
+ }
+@@ -1349,13 +1424,13 @@ int dev_queue_xmit(struct sk_buff *skb)
+ }
+
+ 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;
+ }
+
+@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
+ 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);
+@@ -2714,9 +2789,7 @@ int register_netdevice(struct net_device
+
+ /* 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;
+@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
+ 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);
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev_mcast.c ./net/core/dev_mcast.c
+--- ../orig-linux-2.6.16.29/net/core/dev_mcast.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/core/dev_mcast.c 2006-09-19 13:59:20.000000000 +0100
+@@ -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 @@ static void __dev_mc_upload(struct net_d
+
+ 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 dev_mc_delete(struct net_device *dev
+ 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 @@ int dev_mc_delete(struct net_device *dev
+ */
+ __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 @@ int dev_mc_add(struct net_device *dev, v
+
+ 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 @@ int dev_mc_add(struct net_device *dev, v
+ }
+
+ 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 @@ int dev_mc_add(struct net_device *dev, v
+
+ __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 @@ done:
+
+ 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 @@ void dev_mc_discard(struct net_device *d
+ }
+ dev->mc_count = 0;
+
+- spin_unlock_bh(&dev->xmit_lock);
++ netif_tx_unlock_bh(dev);
+ }
+
+ #ifdef CONFIG_PROC_FS
+@@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_fi
+ 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 @@ static int dev_mc_seq_show(struct seq_fi
+
+ seq_putc(seq, '\n');
+ }
+- spin_unlock_bh(&dev->xmit_lock);
++ netif_tx_unlock_bh(dev);
+ return 0;
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/net/core/ethtool.c ./net/core/ethtool.c
+--- ../orig-linux-2.6.16.29/net/core/ethtool.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/core/ethtool.c 2006-09-19 13:59:20.000000000 +0100
+@@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_devic
+
+ 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 @@ static int ethtool_set_sg(struct net_dev
+ 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_set_sg(struct net_dev
+
+ 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 @@ static int ethtool_set_ufo(struct net_de
+ 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 @@ int dev_ethtool(struct ifreq *ifr)
+ 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;
+ }
+diff -pruN ../orig-linux-2.6.16.29/net/core/netpoll.c ./net/core/netpoll.c
+--- ../orig-linux-2.6.16.29/net/core/netpoll.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/core/netpoll.c 2006-09-19 13:59:20.000000000 +0100
+@@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netp
+
+ 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) {
+diff -pruN ../orig-linux-2.6.16.29/net/core/pktgen.c ./net/core/pktgen.c
+--- ../orig-linux-2.6.16.29/net/core/pktgen.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/core/pktgen.c 2006-09-19 13:59:20.000000000 +0100
+@@ -2586,7 +2586,7 @@ static __inline__ void pktgen_xmit(struc
+ }
+ }
+
+- 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 @@ retry_now:
+ 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)) {
+diff -pruN ../orig-linux-2.6.16.29/net/core/skbuff.c ./net/core/skbuff.c
+--- ../orig-linux-2.6.16.29/net/core/skbuff.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/core/skbuff.c 2006-09-19 13:59:20.000000000 +0100
+@@ -164,9 +164,9 @@ struct sk_buff *__alloc_skb(unsigned int
+ 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,8 +230,9 @@ struct sk_buff *alloc_skb_from_cache(kme
+
+ 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)->gso_size = 0;
++ skb_shinfo(skb)->gso_segs = 0;
++ skb_shinfo(skb)->gso_type = 0;
+ skb_shinfo(skb)->frag_list = NULL;
+ out:
+ return skb;
+@@ -501,8 +502,9 @@ static void copy_skb_header(struct sk_bu
+ 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)->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;
+ }
+
+ /**
+@@ -1777,6 +1779,133 @@ int skb_append_datato_frags(struct sock
+ 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",
+diff -pruN ../orig-linux-2.6.16.29/net/decnet/dn_nsp_in.c
./net/decnet/dn_nsp_in.c
+--- ../orig-linux-2.6.16.29/net/decnet/dn_nsp_in.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/decnet/dn_nsp_in.c 2006-09-19 13:59:20.000000000 +0100
+@@ -801,8 +801,7 @@ got_it:
+ * 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;
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/net/decnet/dn_route.c
./net/decnet/dn_route.c
+--- ../orig-linux-2.6.16.29/net/decnet/dn_route.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/decnet/dn_route.c 2006-09-19 13:59:20.000000000 +0100
+@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, st
+ 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) {
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/af_inet.c ./net/ipv4/af_inet.c
+--- ../orig-linux-2.6.16.29/net/ipv4/af_inet.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/ipv4/af_inet.c 2006-09-19 13:59:20.000000000 +0100
+@@ -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 @@ int inet_sk_rebuild_header(struct sock *
+
+ 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 igmp_protocol
+ 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 int ipv4_proc_init(void);
+ 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)
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/ip_output.c ./net/ipv4/ip_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/ip_output.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv4/ip_output.c 2006-09-19 13:59:20.000000000 +0100
+@@ -210,8 +210,7 @@ static inline int ip_finish_output(struc
+ 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 @@ packet_routed:
+ }
+
+ 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 @@ static inline int ip_ufo_append_data(str
+ (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 @@ int ip_append_data(struct sock *sk,
+ */
+ 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 @@ ssize_t ip_append_page(struct sock *sk,
+
+ 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 {
+
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/ipcomp.c ./net/ipv4/ipcomp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/ipcomp.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/ipv4/ipcomp.c 2006-09-19 13:59:20.000000000 +0100
+@@ -84,7 +84,7 @@ static int ipcomp_input(struct xfrm_stat
+ 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 @@ static int ipcomp_input(struct xfrm_stat
+ } 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 @@ static int ipcomp_output(struct xfrm_sta
+ 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;
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp.c ./net/ipv4/tcp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/ipv4/tcp.c 2006-09-19 13:59:20.000000000 +0100
+@@ -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 @@ new_segment:
+ 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 tcp_sendpage(struct socket *sock
+ 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 @@ new_segment:
+ /*
+ * 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 @@ new_segment:
+
+ 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 @@ int tcp_getsockopt(struct sock *sk, int
+ }
+
+
++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;
+
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp_input.c ./net/ipv4/tcp_input.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp_input.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv4/tcp_input.c 2006-09-19 13:59:20.000000000 +0100
+@@ -1072,7 +1072,7 @@ tcp_sacktag_write_queue(struct sock *sk,
+ 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);
+ }
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp_output.c
./net/ipv4/tcp_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp_output.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv4/tcp_output.c 2006-09-19 13:59:20.000000000 +0100
+@@ -497,15 +497,17 @@ static void tcp_set_skb_tso_segs(struct
+ /* 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,7 +852,7 @@ static int tcp_init_tso_segs(struct sock
+
+ if (!tso_segs ||
+ (tso_segs > 1 &&
+- skb_shinfo(skb)->tso_size != mss_now)) {
++ tcp_skb_mss(skb) != mss_now)) {
+ tcp_set_skb_tso_segs(sk, skb, mss_now);
+ tso_segs = tcp_skb_pcount(skb);
+ }
+@@ -1510,8 +1512,9 @@ int tcp_retransmit_skb(struct sock *sk,
+ tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
+ if (!pskb_trim(skb, 0)) {
+ TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
+- 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;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->csum = 0;
+ }
+@@ -1716,8 +1719,9 @@ void tcp_send_fin(struct sock *sk)
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
+ TCP_SKB_CB(skb)->sacked = 0;
+- 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;
+
+ /* FIN eats a sequence byte, write_seq advanced by
tcp_queue_skb(). */
+ TCP_SKB_CB(skb)->seq = tp->write_seq;
+@@ -1749,8 +1753,9 @@ void tcp_send_active_reset(struct sock *
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
+ TCP_SKB_CB(skb)->sacked = 0;
+- 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;
+
+ /* Send it off. */
+ TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
+@@ -1833,8 +1838,9 @@ struct sk_buff * tcp_make_synack(struct
+ TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
+ TCP_SKB_CB(skb)->sacked = 0;
+- 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;
+ th->seq = htonl(TCP_SKB_CB(skb)->seq);
+ th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
+ if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
+@@ -1937,8 +1943,9 @@ int tcp_connect(struct sock *sk)
+ TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
+ TCP_ECN_send_syn(sk, tp, buff);
+ TCP_SKB_CB(buff)->sacked = 0;
+- skb_shinfo(buff)->tso_segs = 1;
+- skb_shinfo(buff)->tso_size = 0;
++ skb_shinfo(buff)->gso_segs = 1;
++ skb_shinfo(buff)->gso_size = 0;
++ skb_shinfo(buff)->gso_type = 0;
+ buff->csum = 0;
+ TCP_SKB_CB(buff)->seq = tp->write_seq++;
+ TCP_SKB_CB(buff)->end_seq = tp->write_seq;
+@@ -2042,8 +2049,9 @@ void tcp_send_ack(struct sock *sk)
+ buff->csum = 0;
+ TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(buff)->sacked = 0;
+- skb_shinfo(buff)->tso_segs = 1;
+- skb_shinfo(buff)->tso_size = 0;
++ skb_shinfo(buff)->gso_segs = 1;
++ skb_shinfo(buff)->gso_size = 0;
++ skb_shinfo(buff)->gso_type = 0;
+
+ /* Send it off, this clears delayed acks for us. */
+ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq =
tcp_acceptable_seq(sk, tp);
+@@ -2078,8 +2086,9 @@ static int tcp_xmit_probe_skb(struct soc
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(skb)->sacked = urgent;
+- 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;
+
+ /* Use a previous sequence. This should cause the other
+ * end to send an ack. Don't queue or clone SKB, just
+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-19
13:59:15.000000000 +0100
++++ ./net/ipv4/xfrm4_output.c 2006-09-19 13:59:20.000000000 +0100
+@@ -9,6 +9,8 @@
+ */
+
+ #include <linux/compiler.h>
++#include <linux/if_ether.h>
++#include <linux/kernel.h>
+ #include <linux/skbuff.h>
+ #include <linux/spinlock.h>
+ #include <linux/netfilter_ipv4.h>
+@@ -158,16 +160,10 @@ error_nolock:
+ goto out_exit;
+ }
+
+-static int xfrm4_output_finish(struct sk_buff *skb)
++static int xfrm4_output_finish2(struct sk_buff *skb)
+ {
+ int err;
+
+-#ifdef CONFIG_NETFILTER
+- if (!skb->dst->xfrm) {
+- IPCB(skb)->flags |= IPSKB_REROUTED;
+- return dst_output(skb);
+- }
+-#endif
+ while (likely((err = xfrm4_output_one(skb)) == 0)) {
+ nf_reset(skb);
+
+@@ -180,7 +176,7 @@ static int xfrm4_output_finish(struct sk
+ return dst_output(skb);
+
+ err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
+- skb->dst->dev, xfrm4_output_finish);
++ skb->dst->dev, xfrm4_output_finish2);
+ if (unlikely(err != 1))
+ break;
+ }
+@@ -188,6 +184,48 @@ static int xfrm4_output_finish(struct sk
+ return err;
+ }
+
++static int xfrm4_output_finish(struct sk_buff *skb)
++{
++ struct sk_buff *segs;
++
++#ifdef CONFIG_NETFILTER
++ if (!skb->dst->xfrm) {
++ IPCB(skb)->flags |= IPSKB_REROUTED;
++ return dst_output(skb);
++ }
++#endif
++
++ if (!skb_shinfo(skb)->gso_size)
++ return xfrm4_output_finish2(skb);
++
++ skb->protocol = htons(ETH_P_IP);
++ segs = skb_gso_segment(skb, 0);
++ kfree_skb(skb);
++ if (unlikely(IS_ERR(segs)))
++ return PTR_ERR(segs);
++
++ do {
++ struct sk_buff *nskb = segs->next;
++ int err;
++
++ segs->next = NULL;
++ err = xfrm4_output_finish2(segs);
++
++ if (unlikely(err)) {
++ while ((segs = nskb)) {
++ nskb = segs->next;
++ segs->next = NULL;
++ kfree_skb(segs);
++ }
++ return err;
++ }
++
++ segs = nskb;
++ } while (segs);
++
++ return 0;
++}
++
+ int xfrm4_output(struct sk_buff *skb)
+ {
+ return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
skb->dst->dev,
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c
./net/ipv6/ip6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv6/ip6_output.c 2006-09-19 13:59:20.000000000 +0100
+@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
+
+ int ip6_output(struct sk_buff *skb)
+ {
+- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
++ if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
+ dst_allfrag(skb->dst))
+ return ip6_fragment(skb, ip6_output2);
+ else
+@@ -829,8 +829,9 @@ static inline int ip6_ufo_append_data(st
+ struct frag_hdr fhdr;
+
+ /* specify the length of each IP datagram fragment*/
+- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) -
+- sizeof(struct frag_hdr);
++ skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
++ sizeof(struct frag_hdr);
++ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
+ ipv6_select_ident(skb, &fhdr);
+ skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
+ __skb_queue_tail(&sk->sk_write_queue, skb);
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/ipcomp6.c ./net/ipv6/ipcomp6.c
+--- ../orig-linux-2.6.16.29/net/ipv6/ipcomp6.c 2006-09-12 19:02:10.000000000
+0100
++++ ./net/ipv6/ipcomp6.c 2006-09-19 13:59:20.000000000 +0100
+@@ -64,7 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
+
+ static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state
*decap, struct sk_buff *skb)
+ {
+- int err = 0;
++ int err = -ENOMEM;
+ u8 nexthdr = 0;
+ int hdr_len = skb->h.raw - skb->nh.raw;
+ unsigned char *tmp_hdr = NULL;
+@@ -75,11 +75,8 @@ static int ipcomp6_input(struct xfrm_sta
+ struct crypto_tfm *tfm;
+ int cpu;
+
+- 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;
+
+@@ -158,10 +155,8 @@ static int ipcomp6_output(struct xfrm_st
+ 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;
+- }
+
+ /* compression */
+ plen = skb->len - hdr_len;
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c
./net/ipv6/xfrm6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv6/xfrm6_output.c 2006-09-19 13:59:20.000000000 +0100
+@@ -151,7 +151,7 @@ error_nolock:
+ goto out_exit;
+ }
+
+-static int xfrm6_output_finish(struct sk_buff *skb)
++static int xfrm6_output_finish2(struct sk_buff *skb)
+ {
+ int err;
+
+@@ -167,7 +167,7 @@ static int xfrm6_output_finish(struct sk
+ return dst_output(skb);
+
+ err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
+- skb->dst->dev, xfrm6_output_finish);
++ skb->dst->dev, xfrm6_output_finish2);
+ if (unlikely(err != 1))
+ break;
+ }
+@@ -175,6 +175,41 @@ static int xfrm6_output_finish(struct sk
+ return err;
+ }
+
++static int xfrm6_output_finish(struct sk_buff *skb)
++{
++ struct sk_buff *segs;
++
++ if (!skb_shinfo(skb)->gso_size)
++ return xfrm6_output_finish2(skb);
++
++ skb->protocol = htons(ETH_P_IP);
++ segs = skb_gso_segment(skb, 0);
++ kfree_skb(skb);
++ if (unlikely(IS_ERR(segs)))
++ return PTR_ERR(segs);
++
++ do {
++ struct sk_buff *nskb = segs->next;
++ int err;
++
++ segs->next = NULL;
++ err = xfrm6_output_finish2(segs);
++
++ if (unlikely(err)) {
++ while ((segs = nskb)) {
++ nskb = segs->next;
++ segs->next = NULL;
++ kfree_skb(segs);
++ }
++ return err;
++ }
++
++ segs = nskb;
++ } while (segs);
++
++ return 0;
++}
++
+ int xfrm6_output(struct sk_buff *skb)
+ {
+ return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
+diff -pruN ../orig-linux-2.6.16.29/net/sched/sch_generic.c
./net/sched/sch_generic.c
+--- ../orig-linux-2.6.16.29/net/sched/sch_generic.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/sched/sch_generic.c 2006-09-19 13:59:20.000000000 +0100
+@@ -72,9 +72,9 @@ void qdisc_unlock_tree(struct net_device
+ dev->queue_lock serializes queue accesses for this device
+ AND dev->qdisc pointer itself.
+
+- dev->xmit_lock serializes accesses to device driver.
++ netif_tx_lock serializes accesses to device driver.
+
+- dev->queue_lock and dev->xmit_lock are mutually exclusive,
++ dev->queue_lock and netif_tx_lock are mutually exclusive,
+ if one is grabbed, another must be free.
+ */
+
+@@ -90,14 +90,17 @@ void qdisc_unlock_tree(struct net_device
+ NOTE: Called under dev->queue_lock with locally disabled BH.
+ */
+
+-int qdisc_restart(struct net_device *dev)
++static inline int qdisc_restart(struct net_device *dev)
+ {
+ struct Qdisc *q = dev->qdisc;
+ struct sk_buff *skb;
+
+ /* Dequeue packet */
+- if ((skb = q->dequeue(q)) != NULL) {
++ if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
+ unsigned nolock = (dev->features & NETIF_F_LLTX);
++
++ dev->gso_skb = NULL;
++
+ /*
+ * When the driver has LLTX set it does its own locking
+ * in start_xmit. No need to add additional overhead by
+@@ -108,7 +111,7 @@ int qdisc_restart(struct net_device *dev
+ * will be requeued.
+ */
+ if (!nolock) {
+- if (!spin_trylock(&dev->xmit_lock)) {
++ if (!netif_tx_trylock(dev)) {
+ collision:
+ /* So, someone grabbed the driver. */
+
+@@ -126,8 +129,6 @@ int qdisc_restart(struct net_device *dev
+ __get_cpu_var(netdev_rx_stat).cpu_collision++;
+ goto requeue;
+ }
+- /* Remember that the driver is grabbed by us. */
+- dev->xmit_lock_owner = smp_processor_id();
+ }
+
+ {
+@@ -136,14 +137,11 @@ int qdisc_restart(struct net_device *dev
+
+ if (!netif_queue_stopped(dev)) {
+ int ret;
+- if (netdev_nit)
+- dev_queue_xmit_nit(skb, dev);
+
+- ret = dev->hard_start_xmit(skb, dev);
++ ret = dev_hard_start_xmit(skb, dev);
+ if (ret == NETDEV_TX_OK) {
+ if (!nolock) {
+- dev->xmit_lock_owner = -1;
+- spin_unlock(&dev->xmit_lock);
++ netif_tx_unlock(dev);
+ }
+ spin_lock(&dev->queue_lock);
+ return -1;
+@@ -157,8 +155,7 @@ int qdisc_restart(struct net_device *dev
+ /* NETDEV_TX_BUSY - we need to requeue */
+ /* Release the driver */
+ if (!nolock) {
+- dev->xmit_lock_owner = -1;
+- spin_unlock(&dev->xmit_lock);
++ netif_tx_unlock(dev);
+ }
+ spin_lock(&dev->queue_lock);
+ q = dev->qdisc;
+@@ -175,7 +172,10 @@ int qdisc_restart(struct net_device *dev
+ */
+
+ requeue:
+- q->ops->requeue(skb, q);
++ if (skb->next)
++ dev->gso_skb = skb;
++ else
++ q->ops->requeue(skb, q);
+ netif_schedule(dev);
+ return 1;
+ }
+@@ -183,11 +183,23 @@ requeue:
+ return q->q.qlen;
+ }
+
++void __qdisc_run(struct net_device *dev)
++{
++ if (unlikely(dev->qdisc == &noop_qdisc))
++ goto out;
++
++ while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
++ /* NOTHING */;
++
++out:
++ clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
++}
++
+ static void dev_watchdog(unsigned long arg)
+ {
+ struct net_device *dev = (struct net_device *)arg;
+
+- spin_lock(&dev->xmit_lock);
++ netif_tx_lock(dev);
+ if (dev->qdisc != &noop_qdisc) {
+ if (netif_device_present(dev) &&
+ netif_running(dev) &&
+@@ -201,7 +213,7 @@ static void dev_watchdog(unsigned long a
+ dev_hold(dev);
+ }
+ }
+- spin_unlock(&dev->xmit_lock);
++ netif_tx_unlock(dev);
+
+ dev_put(dev);
+ }
+@@ -225,17 +237,17 @@ void __netdev_watchdog_up(struct net_dev
+
+ static void dev_watchdog_up(struct net_device *dev)
+ {
+- spin_lock_bh(&dev->xmit_lock);
++ netif_tx_lock_bh(dev);
+ __netdev_watchdog_up(dev);
+- spin_unlock_bh(&dev->xmit_lock);
++ netif_tx_unlock_bh(dev);
+ }
+
+ static void dev_watchdog_down(struct net_device *dev)
+ {
+- spin_lock_bh(&dev->xmit_lock);
++ netif_tx_lock_bh(dev);
+ if (del_timer(&dev->watchdog_timer))
+ __dev_put(dev);
+- spin_unlock_bh(&dev->xmit_lock);
++ netif_tx_unlock_bh(dev);
+ }
+
+ void netif_carrier_on(struct net_device *dev)
+@@ -577,10 +589,17 @@ void dev_deactivate(struct net_device *d
+
+ dev_watchdog_down(dev);
+
+- while (test_bit(__LINK_STATE_SCHED, &dev->state))
++ /* Wait for outstanding dev_queue_xmit calls. */
++ synchronize_rcu();
++
++ /* Wait for outstanding qdisc_run calls. */
++ while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
+ yield();
+
+- spin_unlock_wait(&dev->xmit_lock);
++ if (dev->gso_skb) {
++ kfree_skb(dev->gso_skb);
++ dev->gso_skb = NULL;
++ }
+ }
+
+ void dev_init_scheduler(struct net_device *dev)
+@@ -622,6 +641,5 @@ EXPORT_SYMBOL(qdisc_create_dflt);
+ EXPORT_SYMBOL(qdisc_alloc);
+ EXPORT_SYMBOL(qdisc_destroy);
+ EXPORT_SYMBOL(qdisc_reset);
+-EXPORT_SYMBOL(qdisc_restart);
+ EXPORT_SYMBOL(qdisc_lock_tree);
+ EXPORT_SYMBOL(qdisc_unlock_tree);
+diff -pruN ../orig-linux-2.6.16.29/net/sched/sch_teql.c ./net/sched/sch_teql.c
+--- ../orig-linux-2.6.16.29/net/sched/sch_teql.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/sched/sch_teql.c 2006-09-19 13:59:20.000000000 +0100
+@@ -302,20 +302,17 @@ restart:
+
+ switch (teql_resolve(skb, skb_res, slave)) {
+ case 0:
+- if (spin_trylock(&slave->xmit_lock)) {
+- slave->xmit_lock_owner = smp_processor_id();
++ if (netif_tx_trylock(slave)) {
+ if (!netif_queue_stopped(slave) &&
+ slave->hard_start_xmit(skb, slave) == 0) {
+- slave->xmit_lock_owner = -1;
+- spin_unlock(&slave->xmit_lock);
++ netif_tx_unlock(slave);
+ master->slaves = NEXT_SLAVE(q);
+ netif_wake_queue(dev);
+ master->stats.tx_packets++;
+ master->stats.tx_bytes += len;
+ return 0;
+ }
+- slave->xmit_lock_owner = -1;
+- spin_unlock(&slave->xmit_lock);
++ netif_tx_unlock(slave);
+ }
+ if (netif_queue_stopped(dev))
+ busy = 1;
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/net-gso-1-check-dodgy.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-gso-1-check-dodgy.patch Tue Sep 19
14:26:47 2006 +0100
@@ -0,0 +1,27 @@
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp.c ./net/ipv4/tcp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp.c 2006-09-19 13:59:20.000000000
+0100
++++ ./net/ipv4/tcp.c 2006-09-19 13:59:42.000000000 +0100
+@@ -2042,13 +2042,19 @@ struct sk_buff *tcp_tso_segment(struct s
+ 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);
+
++ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
++ /* Packet is from an untrusted source, reset gso_segs. */
++ int mss = skb_shinfo(skb)->gso_size;
++
++ skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
++
++ segs = NULL;
++ goto out;
++ }
++
+ segs = skb_segment(skb, features);
+ if (IS_ERR(segs))
+ goto out;
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/net-gso-2-checksum-fix.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-gso-2-checksum-fix.patch Tue Sep 19
14:26:47 2006 +0100
@@ -0,0 +1,451 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/bnx2.c ./drivers/net/bnx2.c
+--- ../orig-linux-2.6.16.29/drivers/net/bnx2.c 2006-09-19 13:59:20.000000000
+0100
++++ ./drivers/net/bnx2.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
+ skb = tx_buf->skb;
+ #ifdef BCM_TSO
+ /* partial BD completions possible with TSO packets */
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ u16 last_idx, last_ring_idx;
+
+ last_idx = sw_cons +
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c
./drivers/net/chelsio/sge.c
+--- ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/chelsio/sge.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
+ struct cpl_tx_pkt *cpl;
+
+ #ifdef NETIF_F_TSO
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ int eth_type;
+ struct cpl_tx_pkt_lso *hdr;
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c
./drivers/net/e1000/e1000_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/e1000/e1000_main.c 2006-09-19 13:59:46.000000000 +0100
+@@ -2526,7 +2526,7 @@ e1000_tso(struct e1000_adapter *adapter,
+ uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
+ int err;
+
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+@@ -2651,7 +2651,7 @@ e1000_tx_map(struct e1000_adapter *adapt
+ * 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)->gso_size) {
++ !skb_is_gso(skb)) {
+ tx_ring->last_tx_tso = 0;
+ size -= 4;
+ }
+@@ -2934,8 +2934,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
+
+ #ifdef NETIF_F_TSO
+ /* Controller Erratum workaround */
+- if (!skb->data_len && tx_ring->last_tx_tso &&
+- !skb_shinfo(skb)->gso_size)
++ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
+ count++;
+ #endif
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/forcedeth.c
./drivers/net/forcedeth.c
+--- ../orig-linux-2.6.16.29/drivers/net/forcedeth.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/forcedeth.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1105,7 +1105,7 @@ static int nv_start_xmit(struct sk_buff
+ np->tx_skbuff[nr] = skb;
+
+ #ifdef NETIF_F_TSO
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size <<
NV_TX2_TSO_SHIFT);
+ else
+ #endif
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c
./drivers/net/ixgb/ixgb_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/ixgb/ixgb_main.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1163,7 +1163,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+ uint16_t ipcse, tucse, mss;
+ int err;
+
+- if(likely(skb_shinfo(skb)->gso_size)) {
++ if (likely(skb_is_gso(skb))) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/loopback.c
./drivers/net/loopback.c
+--- ../orig-linux-2.6.16.29/drivers/net/loopback.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/loopback.c 2006-09-19 13:59:46.000000000 +0100
+@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff
+ #endif
+
+ #ifdef LOOPBACK_TSO
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ BUG_ON(skb->protocol != htons(ETH_P_IP));
+ BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/sky2.c ./drivers/net/sky2.c
+--- ../orig-linux-2.6.16.29/drivers/net/sky2.c 2006-09-19 13:59:20.000000000
+0100
++++ ./drivers/net/sky2.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
+ count = sizeof(dma_addr_t) / sizeof(u32);
+ count += skb_shinfo(skb)->nr_frags * count;
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ ++count;
+
+ if (skb->ip_summed == CHECKSUM_HW)
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/typhoon.c
./drivers/net/typhoon.c
+--- ../orig-linux-2.6.16.29/drivers/net/typhoon.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/net/typhoon.c 2006-09-19 13:59:46.000000000 +0100
+@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
+ * If problems develop with TSO, check this first.
+ */
+ numDesc = skb_shinfo(skb)->nr_frags + 1;
+- if(skb_tso_size(skb))
++ if (skb_is_gso(skb))
+ numDesc++;
+
+ /* When checking for free space in the ring, we need to also
+@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st
+ TYPHOON_TX_PF_VLAN_TAG_SHIFT);
+ }
+
+- if(skb_tso_size(skb)) {
++ if (skb_is_gso(skb)) {
+ first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
+ first_txd->numDesc++;
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c
./drivers/s390/net/qeth_main.c
+--- ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c 2006-09-19
13:59:20.000000000 +0100
++++ ./drivers/s390/net/qeth_main.c 2006-09-19 13:59:46.000000000 +0100
+@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
+ queue = card->qdio.out_qs
+ [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ large_send = card->options.large_send;
+
+ /*are we able to do TSO ? If so ,prepare and send it from here */
+@@ -4501,8 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
+ card->stats.tx_packets++;
+ card->stats.tx_bytes += skb->len;
+ #ifdef CONFIG_QETH_PERF_STATS
+- if (skb_shinfo(skb)->gso_size &&
+- !(large_send == QETH_LARGE_SEND_NO)) {
++ if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) {
+ card->perf_stats.large_send_bytes += skb->len;
+ card->perf_stats.large_send_cnt++;
+ }
+diff -pruN ../orig-linux-2.6.16.29/include/linux/netdevice.h
./include/linux/netdevice.h
+--- ../orig-linux-2.6.16.29/include/linux/netdevice.h 2006-09-19
13:59:20.000000000 +0100
++++ ./include/linux/netdevice.h 2006-09-19 13:59:46.000000000 +0100
+@@ -541,6 +541,7 @@ struct packet_type {
+ struct net_device *);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb,
+ int features);
++ int (*gso_send_check)(struct sk_buff *skb);
+ void *af_packet_priv;
+ struct list_head list;
+ };
+@@ -1001,14 +1002,15 @@ 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;
++ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
+ 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);
++ return skb_is_gso(skb) &&
++ (!skb_gso_ok(skb, dev->features) ||
++ unlikely(skb->ip_summed != CHECKSUM_HW));
+ }
+
+ #endif /* __KERNEL__ */
+diff -pruN ../orig-linux-2.6.16.29/include/linux/skbuff.h
./include/linux/skbuff.h
+--- ../orig-linux-2.6.16.29/include/linux/skbuff.h 2006-09-19
13:59:20.000000000 +0100
++++ ./include/linux/skbuff.h 2006-09-19 13:59:46.000000000 +0100
+@@ -1403,5 +1403,10 @@ static inline void nf_bridge_get(struct
+ static inline void nf_reset(struct sk_buff *skb) {}
+ #endif /* CONFIG_NETFILTER */
+
++static inline int skb_is_gso(const struct sk_buff *skb)
++{
++ return skb_shinfo(skb)->gso_size;
++}
++
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_SKBUFF_H */
+diff -pruN ../orig-linux-2.6.16.29/include/net/protocol.h
./include/net/protocol.h
+--- ../orig-linux-2.6.16.29/include/net/protocol.h 2006-09-19
13:59:20.000000000 +0100
++++ ./include/net/protocol.h 2006-09-19 13:59:46.000000000 +0100
+@@ -37,6 +37,7 @@
+ struct net_protocol {
+ int (*handler)(struct sk_buff *skb);
+ void (*err_handler)(struct sk_buff *skb, u32 info);
++ int (*gso_send_check)(struct sk_buff *skb);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb,
+ int features);
+ int no_policy;
+diff -pruN ../orig-linux-2.6.16.29/include/net/tcp.h ./include/net/tcp.h
+--- ../orig-linux-2.6.16.29/include/net/tcp.h 2006-09-19 13:59:20.000000000
+0100
++++ ./include/net/tcp.h 2006-09-19 13:59:46.000000000 +0100
+@@ -1063,6 +1063,7 @@ extern struct request_sock_ops tcp_reque
+
+ extern int tcp_v4_destroy_sock(struct sock *sk);
+
++extern int tcp_v4_gso_send_check(struct sk_buff *skb);
+ extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
+
+ #ifdef CONFIG_PROC_FS
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_forward.c
./net/bridge/br_forward.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_forward.c 2006-09-19
13:59:20.000000000 +0100
++++ ./net/bridge/br_forward.c 2006-09-19 13:59:46.000000000 +0100
+@@ -32,7 +32,7 @@ static inline int should_deliver(const s
+ 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)->gso_size)
++ if (skb->len > skb->dev->mtu && !skb_is_gso(skb))
+ kfree_skb(skb);
+ else {
+ #ifdef CONFIG_BRIDGE_NETFILTER
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c
./net/bridge/br_netfilter.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c 2006-09-19
13:59:20.000000000 +0100
++++ ./net/bridge/br_netfilter.c 2006-09-19 13:59:46.000000000 +0100
+@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
+ {
+ if (skb->protocol == htons(ETH_P_IP) &&
+ skb->len > skb->dev->mtu &&
+- !skb_shinfo(skb)->gso_size)
++ !skb_is_gso(skb))
+ return ip_fragment(skb, br_dev_queue_push_xmit);
+ else
+ return br_dev_queue_push_xmit(skb);
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.16.29/net/core/dev.c 2006-09-19 13:59:20.000000000
+0100
++++ ./net/core/dev.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1083,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk
+ unsigned int csum;
+ int ret = 0, offset = skb->h.raw - skb->data;
+
+- if (inward) {
+- skb->ip_summed = CHECKSUM_NONE;
+- goto out;
++ if (inward)
++ goto out_set_summed;
++
++ if (unlikely(skb_shinfo(skb)->gso_size)) {
++ static int warned;
++
++ WARN_ON(!warned);
++ warned = 1;
++
++ /* Let GSO fix up the checksum. */
++ goto out_set_summed;
+ }
+
+ if (skb_cloned(skb)) {
+@@ -1102,6 +1110,8 @@ int skb_checksum_help(struct sk_buff *sk
+ BUG_ON(skb->csum + 2 > offset);
+
+ *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
++
++out_set_summed:
+ skb->ip_summed = CHECKSUM_NONE;
+ out:
+ return ret;
+@@ -1122,17 +1132,35 @@ struct sk_buff *skb_gso_segment(struct s
+ struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+ struct packet_type *ptype;
+ int type = skb->protocol;
++ int err;
+
+ 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);
+
++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ static int warned;
++
++ WARN_ON(!warned);
++ warned = 1;
++
++ if (skb_header_cloned(skb) &&
++ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
++ return ERR_PTR(err);
++ }
++
+ rcu_read_lock();
+ list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
+ if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ err = ptype->gso_send_check(skb);
++ segs = ERR_PTR(err);
++ if (err || skb_gso_ok(skb, features))
++ break;
++ __skb_push(skb, skb->data - skb->nh.raw);
++ }
+ segs = ptype->gso_segment(skb, features);
+ break;
+ }
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/af_inet.c ./net/ipv4/af_inet.c
+--- ../orig-linux-2.6.16.29/net/ipv4/af_inet.c 2006-09-19 13:59:20.000000000
+0100
++++ ./net/ipv4/af_inet.c 2006-09-19 13:59:46.000000000 +0100
+@@ -1085,6 +1085,40 @@ int inet_sk_rebuild_header(struct sock *
+
+ EXPORT_SYMBOL(inet_sk_rebuild_header);
+
++static int inet_gso_send_check(struct sk_buff *skb)
++{
++ struct iphdr *iph;
++ struct net_protocol *ops;
++ int proto;
++ int ihl;
++ int err = -EINVAL;
++
++ if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
++ goto out;
++
++ iph = skb->nh.iph;
++ ihl = iph->ihl * 4;
++ if (ihl < sizeof(*iph))
++ goto out;
++
++ if (unlikely(!pskb_may_pull(skb, ihl)))
++ goto out;
++
++ skb->h.raw = __skb_pull(skb, ihl);
++ iph = skb->nh.iph;
++ proto = iph->protocol & (MAX_INET_PROTOS - 1);
++ err = -EPROTONOSUPPORT;
++
++ rcu_read_lock();
++ ops = rcu_dereference(inet_protos[proto]);
++ if (likely(ops && ops->gso_send_check))
++ err = ops->gso_send_check(skb);
++ rcu_read_unlock();
++
++out:
++ return err;
++}
++
+ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
+ {
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+@@ -1142,6 +1176,7 @@ static struct net_protocol igmp_protocol
+ static struct net_protocol tcp_protocol = {
+ .handler = tcp_v4_rcv,
+ .err_handler = tcp_v4_err,
++ .gso_send_check = tcp_v4_gso_send_check,
+ .gso_segment = tcp_tso_segment,
+ .no_policy = 1,
+ };
+@@ -1188,6 +1223,7 @@ static int ipv4_proc_init(void);
+ static struct packet_type ip_packet_type = {
+ .type = __constant_htons(ETH_P_IP),
+ .func = ip_rcv,
++ .gso_send_check = inet_gso_send_check,
+ .gso_segment = inet_gso_segment,
+ };
+
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/ip_output.c ./net/ipv4/ip_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/ip_output.c 2006-09-19
13:59:20.000000000 +0100
++++ ./net/ipv4/ip_output.c 2006-09-19 13:59:46.000000000 +0100
+@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc
+ return dst_output(skb);
+ }
+ #endif
+- if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
++ if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
+ return ip_fragment(skb, ip_finish_output2);
+ else
+ return ip_finish_output2(skb);
+@@ -1095,7 +1095,7 @@ ssize_t ip_append_page(struct sock *sk,
+ while (size > 0) {
+ int i;
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ len = size;
+ else {
+
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp_ipv4.c ./net/ipv4/tcp_ipv4.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp_ipv4.c 2006-09-12
19:02:10.000000000 +0100
++++ ./net/ipv4/tcp_ipv4.c 2006-09-19 13:59:46.000000000 +0100
+@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk,
+ }
+ }
+
++int tcp_v4_gso_send_check(struct sk_buff *skb)
++{
++ struct iphdr *iph;
++ struct tcphdr *th;
++
++ if (!pskb_may_pull(skb, sizeof(*th)))
++ return -EINVAL;
++
++ iph = skb->nh.iph;
++ th = skb->h.th;
++
++ th->check = 0;
++ th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
++ skb->csum = offsetof(struct tcphdr, check);
++ skb->ip_summed = CHECKSUM_HW;
++ return 0;
++}
++
+ /*
+ * This routine will send an RST to the other tcp.
+ *
+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-19
13:59:20.000000000 +0100
++++ ./net/ipv4/xfrm4_output.c 2006-09-19 13:59:46.000000000 +0100
+@@ -195,7 +195,7 @@ static int xfrm4_output_finish(struct sk
+ }
+ #endif
+
+- if (!skb_shinfo(skb)->gso_size)
++ if (!skb_is_gso(skb))
+ return xfrm4_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c
./net/ipv6/ip6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c 2006-09-19
13:59:20.000000000 +0100
++++ ./net/ipv6/ip6_output.c 2006-09-19 13:59:46.000000000 +0100
+@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
+
+ int ip6_output(struct sk_buff *skb)
+ {
+- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
++ if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
+ dst_allfrag(skb->dst))
+ return ip6_fragment(skb, ip6_output2);
+ else
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c
./net/ipv6/xfrm6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c 2006-09-19
13:59:20.000000000 +0100
++++ ./net/ipv6/xfrm6_output.c 2006-09-19 13:59:46.000000000 +0100
+@@ -179,7 +179,7 @@ static int xfrm6_output_finish(struct sk
+ {
+ struct sk_buff *segs;
+
+- if (!skb_shinfo(skb)->gso_size)
++ if (!skb_is_gso(skb))
+ return xfrm6_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/net-gso-3-fix-errorcheck.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-gso-3-fix-errorcheck.patch Tue Sep 19
14:26:47 2006 +0100
@@ -0,0 +1,17 @@
+diff -pruN ../orig-linux-2.6.16.29/include/linux/netdevice.h
./include/linux/netdevice.h
+--- ../orig-linux-2.6.16.29/include/linux/netdevice.h 2006-09-19
13:59:46.000000000 +0100
++++ ./include/linux/netdevice.h 2006-09-19 14:05:28.000000000 +0100
+@@ -930,10 +930,10 @@ static inline void netif_tx_lock_bh(stru
+
+ static inline int netif_tx_trylock(struct net_device *dev)
+ {
+- int err = spin_trylock(&dev->_xmit_lock);
+- if (!err)
++ int ok = spin_trylock(&dev->_xmit_lock);
++ if (likely(ok))
+ dev->xmit_lock_owner = smp_processor_id();
+- return err;
++ return ok;
+ }
+
+ static inline void netif_tx_unlock(struct net_device *dev)
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/net-gso-4-kill-warnon.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/net-gso-4-kill-warnon.patch Tue Sep 19
14:26:47 2006 +0100
@@ -0,0 +1,27 @@
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.16.29/net/core/dev.c 2006-09-19 13:59:46.000000000
+0100
++++ ./net/core/dev.c 2006-09-19 14:05:32.000000000 +0100
+@@ -1087,11 +1087,6 @@ int skb_checksum_help(struct sk_buff *sk
+ goto out_set_summed;
+
+ if (unlikely(skb_shinfo(skb)->gso_size)) {
+- static int warned;
+-
+- WARN_ON(!warned);
+- warned = 1;
+-
+ /* Let GSO fix up the checksum. */
+ goto out_set_summed;
+ }
+@@ -1141,11 +1136,6 @@ struct sk_buff *skb_gso_segment(struct s
+ __skb_pull(skb, skb->mac_len);
+
+ if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
+- static int warned;
+-
+- WARN_ON(!warned);
+- warned = 1;
+-
+ if (skb_header_cloned(skb) &&
+ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+ return ERR_PTR(err);
diff -r c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/pmd-shared.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/pmd-shared.patch Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,111 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/mm/pageattr.c
./arch/i386/mm/pageattr.c
+--- ../orig-linux-2.6.16.29/arch/i386/mm/pageattr.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/mm/pageattr.c 2006-09-19 14:05:35.000000000 +0100
+@@ -78,7 +78,7 @@ static void set_pmd_pte(pte_t *kpte, uns
+ unsigned long flags;
+
+ set_pte_atomic(kpte, pte); /* change init_mm */
+- if (PTRS_PER_PMD > 1)
++ if (HAVE_SHARED_KERNEL_PMD)
+ return;
+
+ spin_lock_irqsave(&pgd_lock, flags);
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/mm/pgtable.c
./arch/i386/mm/pgtable.c
+--- ../orig-linux-2.6.16.29/arch/i386/mm/pgtable.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/mm/pgtable.c 2006-09-19 14:05:35.000000000 +0100
+@@ -215,9 +215,10 @@ void pgd_ctor(void *pgd, kmem_cache_t *c
+ spin_lock_irqsave(&pgd_lock, flags);
+ }
+
+- clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+- swapper_pg_dir + USER_PTRS_PER_PGD,
+- KERNEL_PGD_PTRS);
++ if (PTRS_PER_PMD == 1 || HAVE_SHARED_KERNEL_PMD)
++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
++ swapper_pg_dir + USER_PTRS_PER_PGD,
++ KERNEL_PGD_PTRS);
+ if (PTRS_PER_PMD > 1)
+ return;
+
+@@ -249,6 +250,30 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
+ goto out_oom;
+ set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
+ }
++
++ if (!HAVE_SHARED_KERNEL_PMD) {
++ unsigned long flags;
++
++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++ pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
++ if (!pmd)
++ goto out_oom;
++ set_pgd(&pgd[USER_PTRS_PER_PGD], __pgd(1 + __pa(pmd)));
++ }
++
++ spin_lock_irqsave(&pgd_lock, flags);
++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++ unsigned long v = (unsigned long)i << PGDIR_SHIFT;
++ pgd_t *kpgd = pgd_offset_k(v);
++ pud_t *kpud = pud_offset(kpgd, v);
++ pmd_t *kpmd = pmd_offset(kpud, v);
++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++ memcpy(pmd, kpmd, PAGE_SIZE);
++ }
++ pgd_list_add(pgd);
++ spin_unlock_irqrestore(&pgd_lock, flags);
++ }
++
+ return pgd;
+
+ out_oom:
+@@ -263,9 +288,23 @@ void pgd_free(pgd_t *pgd)
+ int i;
+
+ /* in the PAE case user pgd entries are overwritten before usage */
+- if (PTRS_PER_PMD > 1)
+- for (i = 0; i < USER_PTRS_PER_PGD; ++i)
+- kmem_cache_free(pmd_cache, (void
*)__va(pgd_val(pgd[i])-1));
++ if (PTRS_PER_PMD > 1) {
++ for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++ kmem_cache_free(pmd_cache, pmd);
++ }
++ if (!HAVE_SHARED_KERNEL_PMD) {
++ unsigned long flags;
++ spin_lock_irqsave(&pgd_lock, flags);
++ pgd_list_del(pgd);
++ spin_unlock_irqrestore(&pgd_lock, flags);
++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
++ kmem_cache_free(pmd_cache, pmd);
++ }
++ }
++ }
+ /* in the non-PAE case, free_pgtables() clears user pgd entries */
+ kmem_cache_free(pgd_cache, pgd);
+ }
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/pgtable-2level-defs.h
./include/asm-i386/pgtable-2level-defs.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/pgtable-2level-defs.h
2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/pgtable-2level-defs.h 2006-09-19 14:05:35.000000000
+0100
+@@ -1,6 +1,8 @@
+ #ifndef _I386_PGTABLE_2LEVEL_DEFS_H
+ #define _I386_PGTABLE_2LEVEL_DEFS_H
+
++#define HAVE_SHARED_KERNEL_PMD 0
++
+ /*
+ * traditional i386 two-level paging structure:
+ */
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/pgtable-3level-defs.h
./include/asm-i386/pgtable-3level-defs.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/pgtable-3level-defs.h
2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/pgtable-3level-defs.h 2006-09-19 14:05:35.000000000
+0100
+@@ -1,6 +1,8 @@
+ #ifndef _I386_PGTABLE_3LEVEL_DEFS_H
+ #define _I386_PGTABLE_3LEVEL_DEFS_H
+
++#define HAVE_SHARED_KERNEL_PMD 1
++
+ /*
+ * PGDIR_SHIFT determines what a top-level page table entry can map
+ */
diff -r c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/rcu_needs_cpu.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/rcu_needs_cpu.patch Tue Sep 19 14:26:47
2006 +0100
@@ -0,0 +1,35 @@
+diff -pruN ../orig-linux-2.6.16.29/include/linux/rcupdate.h
./include/linux/rcupdate.h
+--- ../orig-linux-2.6.16.29/include/linux/rcupdate.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/linux/rcupdate.h 2006-09-19 14:05:39.000000000 +0100
+@@ -134,6 +134,7 @@ static inline void rcu_bh_qsctr_inc(int
+ }
+
+ extern int rcu_pending(int cpu);
++extern int rcu_needs_cpu(int cpu);
+
+ /**
+ * rcu_read_lock - mark the beginning of an RCU read-side critical section.
+diff -pruN ../orig-linux-2.6.16.29/kernel/rcupdate.c ./kernel/rcupdate.c
+--- ../orig-linux-2.6.16.29/kernel/rcupdate.c 2006-09-12 19:02:10.000000000
+0100
++++ ./kernel/rcupdate.c 2006-09-19 14:05:39.000000000 +0100
+@@ -485,6 +485,20 @@ int rcu_pending(int cpu)
+ __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
+ }
+
++/*
++ * Check to see if any future RCU-related work will need to be done
++ * by the current CPU, even if none need be done immediately, returning
++ * 1 if so. This function is part of the RCU implementation; it is -not-
++ * an exported member of the RCU API.
++ */
++int rcu_needs_cpu(int cpu)
++{
++ struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
++ struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
++
++ return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu));
++}
++
+ void rcu_check_callbacks(int cpu, int user)
+ {
+ if (user ||
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++
b/patches/linux-2.6.16.29/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,30 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S
./arch/i386/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/entry.S 2006-09-19 14:05:44.000000000 +0100
+@@ -177,7 +177,7 @@ need_resched:
+
+ # sysenter call handler stub
+ ENTRY(sysenter_entry)
+- movl TSS_sysenter_esp0(%esp),%esp
++ movl SYSENTER_stack_esp0(%esp),%esp
+ sysenter_past_esp:
+ sti
+ pushl $(__USER_DS)
+@@ -492,7 +492,7 @@ device_not_available_emulate:
+ * that sets up the real kernel stack. Check here, since we can't
+ * allow the wrong stack to be used.
+ *
+- * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have
++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have
+ * already pushed 3 words if it hits on the sysenter instruction:
+ * eflags, cs and eip.
+ *
+@@ -504,7 +504,7 @@ device_not_available_emulate:
+ cmpw $__KERNEL_CS,4(%esp); \
+ jne ok; \
+ label: \
+- movl TSS_sysenter_esp0+offset(%esp),%esp; \
++ movl SYSENTER_stack_esp0+offset(%esp),%esp; \
+ pushfl; \
+ pushl $__KERNEL_CS; \
+ pushl $sysenter_past_esp
diff -r c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/series
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/series Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,23 @@
+blktap-aio-16_03_06.patch
+device_bind.patch
+fix-hz-suspend.patch
+fix-ide-cd-pio-mode.patch
+i386-mach-io-check-nmi.patch
+ipv6-no-autoconf.patch
+net-csum.patch
+net-gso-0-base.patch
+net-gso-1-check-dodgy.patch
+net-gso-2-checksum-fix.patch
+net-gso-3-fix-errorcheck.patch
+net-gso-4-kill-warnon.patch
+pmd-shared.patch
+rcu_needs_cpu.patch
+rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
+smp-alts.patch
+tpm_plugin_2.6.17.patch
+x86-increase-interrupt-vector-range.patch
+xen-hotplug.patch
+xenoprof-generic.patch
+x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
+x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
+x86-elfnote-as-preprocessor-macro.patch
diff -r c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/smp-alts.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/smp-alts.patch Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,591 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/Kconfig ./arch/i386/Kconfig
+--- ../orig-linux-2.6.16.29/arch/i386/Kconfig 2006-09-12 19:02:10.000000000
+0100
++++ ./arch/i386/Kconfig 2006-09-19 14:05:48.000000000 +0100
+@@ -202,6 +202,19 @@ config SMP
+
+ If you don't know what to do here, say N.
+
++config SMP_ALTERNATIVES
++ bool "SMP alternatives support (EXPERIMENTAL)"
++ depends on SMP && EXPERIMENTAL
++ help
++ Try to reduce the overhead of running an SMP kernel on a uniprocessor
++ host slightly by replacing certain key instruction sequences
++ according to whether we currently have more than one CPU available.
++ This should provide a noticeable boost to performance when
++ running SMP kernels on UP machines, and have negligible impact
++ when running on an true SMP host.
++
++ If unsure, say N.
++
+ config NR_CPUS
+ int "Maximum number of CPUs (2-255)"
+ range 2 255
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/Makefile
./arch/i386/kernel/Makefile
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/Makefile 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/Makefile 2006-09-19 14:05:48.000000000 +0100
+@@ -37,6 +37,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o
+ obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
+ obj-$(CONFIG_VM86) += vm86.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++obj-$(CONFIG_SMP_ALTERNATIVES) += smpalts.o
+
+ EXTRA_AFLAGS := -traditional
+
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/smpalts.c
./arch/i386/kernel/smpalts.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/smpalts.c 1970-01-01
01:00:00.000000000 +0100
++++ ./arch/i386/kernel/smpalts.c 2006-09-19 14:05:48.000000000 +0100
+@@ -0,0 +1,85 @@
++#include <linux/kernel.h>
++#include <asm/system.h>
++#include <asm/smp_alt.h>
++#include <asm/processor.h>
++#include <asm/string.h>
++
++struct smp_replacement_record {
++ unsigned char targ_size;
++ unsigned char smp1_size;
++ unsigned char smp2_size;
++ unsigned char up_size;
++ unsigned char feature;
++ unsigned char data[0];
++};
++
++struct smp_alternative_record {
++ void *targ_start;
++ struct smp_replacement_record *repl;
++};
++
++extern struct smp_alternative_record __start_smp_alternatives_table,
++ __stop_smp_alternatives_table;
++extern unsigned long __init_begin, __init_end;
++
++void prepare_for_smp(void)
++{
++ struct smp_alternative_record *r;
++ printk(KERN_INFO "Enabling SMP...\n");
++ for (r = &__start_smp_alternatives_table;
++ r != &__stop_smp_alternatives_table;
++ r++) {
++ BUG_ON(r->repl->targ_size < r->repl->smp1_size);
++ BUG_ON(r->repl->targ_size < r->repl->smp2_size);
++ BUG_ON(r->repl->targ_size < r->repl->up_size);
++ if (system_state == SYSTEM_RUNNING &&
++ r->targ_start >= (void *)&__init_begin &&
++ r->targ_start < (void *)&__init_end)
++ continue;
++ if (r->repl->feature != (unsigned char)-1 &&
++ boot_cpu_has(r->repl->feature)) {
++ memcpy(r->targ_start,
++ r->repl->data + r->repl->smp1_size,
++ r->repl->smp2_size);
++ memset(r->targ_start + r->repl->smp2_size,
++ 0x90,
++ r->repl->targ_size - r->repl->smp2_size);
++ } else {
++ memcpy(r->targ_start,
++ r->repl->data,
++ r->repl->smp1_size);
++ memset(r->targ_start + r->repl->smp1_size,
++ 0x90,
++ r->repl->targ_size - r->repl->smp1_size);
++ }
++ }
++ /* Paranoia */
++ asm volatile ("jmp 1f\n1:");
++ mb();
++}
++
++void unprepare_for_smp(void)
++{
++ struct smp_alternative_record *r;
++ printk(KERN_INFO "Disabling SMP...\n");
++ for (r = &__start_smp_alternatives_table;
++ r != &__stop_smp_alternatives_table;
++ r++) {
++ BUG_ON(r->repl->targ_size < r->repl->smp1_size);
++ BUG_ON(r->repl->targ_size < r->repl->smp2_size);
++ BUG_ON(r->repl->targ_size < r->repl->up_size);
++ if (system_state == SYSTEM_RUNNING &&
++ r->targ_start >= (void *)&__init_begin &&
++ r->targ_start < (void *)&__init_end)
++ continue;
++ memcpy(r->targ_start,
++ r->repl->data + r->repl->smp1_size + r->repl->smp2_size,
++ r->repl->up_size);
++ memset(r->targ_start + r->repl->up_size,
++ 0x90,
++ r->repl->targ_size - r->repl->up_size);
++ }
++ /* Paranoia */
++ asm volatile ("jmp 1f\n1:");
++ mb();
++}
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/smpboot.c
./arch/i386/kernel/smpboot.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/smpboot.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/smpboot.c 2006-09-19 14:05:48.000000000 +0100
+@@ -1218,6 +1218,11 @@ static void __init smp_boot_cpus(unsigne
+ if (max_cpus <= cpucount+1)
+ continue;
+
++#ifdef CONFIG_SMP_ALTERNATIVES
++ if (kicked == 1)
++ prepare_for_smp();
++#endif
++
+ if (((cpu = alloc_cpu_id()) <= 0) || do_boot_cpu(apicid, cpu))
+ printk("CPU #%d not responding - cannot use it.\n",
+ apicid);
+@@ -1396,6 +1401,11 @@ int __devinit __cpu_up(unsigned int cpu)
+ return -EIO;
+ }
+
++#ifdef CONFIG_SMP_ALTERNATIVES
++ if (num_online_cpus() == 1)
++ prepare_for_smp();
++#endif
++
+ local_irq_enable();
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+ /* Unleash the CPU! */
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S
./arch/i386/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/vmlinux.lds.S 2006-09-19 14:05:48.000000000 +0100
+@@ -34,6 +34,13 @@ SECTIONS
+ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
+ __stop___ex_table = .;
+
++ . = ALIGN(16);
++ __start_smp_alternatives_table = .;
++ __smp_alternatives : { *(__smp_alternatives) }
++ __stop_smp_alternatives_table = .;
++
++ __smp_replacements : { *(__smp_replacements) }
++
+ RODATA
+
+ /* writeable */
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/atomic.h
./include/asm-i386/atomic.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/atomic.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/atomic.h 2006-09-19 14:05:48.000000000 +0100
+@@ -4,18 +4,13 @@
+ #include <linux/config.h>
+ #include <linux/compiler.h>
+ #include <asm/processor.h>
++#include <asm/smp_alt.h>
+
+ /*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+-#ifdef CONFIG_SMP
+-#define LOCK "lock ; "
+-#else
+-#define LOCK ""
+-#endif
+-
+ /*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/bitops.h
./include/asm-i386/bitops.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/bitops.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/bitops.h 2006-09-19 14:05:48.000000000 +0100
+@@ -7,6 +7,7 @@
+
+ #include <linux/config.h>
+ #include <linux/compiler.h>
++#include <asm/smp_alt.h>
+
+ /*
+ * These have to be done with inline assembly: that way the bit-setting
+@@ -16,12 +17,6 @@
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+-#ifdef CONFIG_SMP
+-#define LOCK_PREFIX "lock ; "
+-#else
+-#define LOCK_PREFIX ""
+-#endif
+-
+ #define ADDR (*(volatile long *) addr)
+
+ /**
+@@ -41,7 +36,7 @@
+ */
+ static inline void set_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btsl %1,%0"
+ :"+m" (ADDR)
+ :"Ir" (nr));
+@@ -76,7 +71,7 @@ static inline void __set_bit(int nr, vol
+ */
+ static inline void clear_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btrl %1,%0"
+ :"+m" (ADDR)
+ :"Ir" (nr));
+@@ -121,7 +116,7 @@ static inline void __change_bit(int nr,
+ */
+ static inline void change_bit(int nr, volatile unsigned long * addr)
+ {
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btcl %1,%0"
+ :"+m" (ADDR)
+ :"Ir" (nr));
+@@ -140,7 +135,7 @@ static inline int test_and_set_bit(int n
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btsl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"+m" (ADDR)
+ :"Ir" (nr) : "memory");
+@@ -180,7 +175,7 @@ static inline int test_and_clear_bit(int
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btrl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"+m" (ADDR)
+ :"Ir" (nr) : "memory");
+@@ -231,7 +226,7 @@ static inline int test_and_change_bit(in
+ {
+ int oldbit;
+
+- __asm__ __volatile__( LOCK_PREFIX
++ __asm__ __volatile__( LOCK
+ "btcl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"+m" (ADDR)
+ :"Ir" (nr) : "memory");
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/futex.h
./include/asm-i386/futex.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/futex.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/futex.h 2006-09-19 14:05:48.000000000 +0100
+@@ -28,7 +28,7 @@
+ "1: movl %2, %0\n\
+ movl %0, %3\n" \
+ insn "\n" \
+-"2: " LOCK_PREFIX "cmpxchgl %3, %2\n\
++"2: " LOCK "cmpxchgl %3, %2\n\
+ jnz 1b\n\
+ 3: .section .fixup,\"ax\"\n\
+ 4: mov %5, %1\n\
+@@ -68,7 +68,7 @@ futex_atomic_op_inuser (int encoded_op,
+ #endif
+ switch (op) {
+ case FUTEX_OP_ADD:
+- __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret,
++ __futex_atomic_op1(LOCK "xaddl %0, %2", ret,
+ oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/rwsem.h
./include/asm-i386/rwsem.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/rwsem.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/rwsem.h 2006-09-19 14:05:48.000000000 +0100
+@@ -40,6 +40,7 @@
+
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
++#include <asm/smp_alt.h>
+
+ struct rwsem_waiter;
+
+@@ -99,7 +100,7 @@ static inline void __down_read(struct rw
+ {
+ __asm__ __volatile__(
+ "# beginning down_read\n\t"
+-LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old
value */
++LOCK " incl (%%eax)\n\t" /* adds 0x00000001, returns the old
value */
+ " js 2f\n\t" /* jump if we weren't granted the lock */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -130,7 +131,7 @@ static inline int __down_read_trylock(st
+ " movl %1,%2\n\t"
+ " addl %3,%2\n\t"
+ " jle 2f\n\t"
+-LOCK_PREFIX " cmpxchgl %2,%0\n\t"
++LOCK " cmpxchgl %2,%0\n\t"
+ " jnz 1b\n\t"
+ "2:\n\t"
+ "# ending __down_read_trylock\n\t"
+@@ -150,7 +151,7 @@ static inline void __down_write(struct r
+ tmp = RWSEM_ACTIVE_WRITE_BIAS;
+ __asm__ __volatile__(
+ "# beginning down_write\n\t"
+-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns
the old value */
++LOCK " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns
the old value */
+ " testl %%edx,%%edx\n\t" /* was the count 0 before? */
+ " jnz 2f\n\t" /* jump if we weren't granted the lock */
+ "1:\n\t"
+@@ -188,7 +189,7 @@ static inline void __up_read(struct rw_s
+ __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
+ __asm__ __volatile__(
+ "# beginning __up_read\n\t"
+-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old
value */
++LOCK " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old
value */
+ " js 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -214,7 +215,7 @@ static inline void __up_write(struct rw_
+ __asm__ __volatile__(
+ "# beginning __up_write\n\t"
+ " movl %2,%%edx\n\t"
+-LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition
0xffff0001 -> 0x00000000 */
++LOCK " xaddl %%edx,(%%eax)\n\t" /* tries to transition
0xffff0001 -> 0x00000000 */
+ " jnz 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -239,7 +240,7 @@ static inline void __downgrade_write(str
+ {
+ __asm__ __volatile__(
+ "# beginning __downgrade_write\n\t"
+-LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 ->
0xYYYY0001 */
++LOCK " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 ->
0xYYYY0001 */
+ " js 2f\n\t" /* jump if the lock is being waited upon */
+ "1:\n\t"
+ LOCK_SECTION_START("")
+@@ -263,7 +264,7 @@ LOCK_PREFIX " addl %2,(%%eax)\n\t"
+ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+ {
+ __asm__ __volatile__(
+-LOCK_PREFIX "addl %1,%0"
++LOCK "addl %1,%0"
+ : "=m"(sem->count)
+ : "ir"(delta), "m"(sem->count));
+ }
+@@ -276,7 +277,7 @@ static inline int rwsem_atomic_update(in
+ int tmp = delta;
+
+ __asm__ __volatile__(
+-LOCK_PREFIX "xadd %0,(%2)"
++LOCK "xadd %0,(%2)"
+ : "+r"(tmp), "=m"(sem->count)
+ : "r"(sem), "m"(sem->count)
+ : "memory");
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/smp_alt.h
./include/asm-i386/smp_alt.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/smp_alt.h 1970-01-01
01:00:00.000000000 +0100
++++ ./include/asm-i386/smp_alt.h 2006-09-19 14:05:48.000000000 +0100
+@@ -0,0 +1,32 @@
++#ifndef __ASM_SMP_ALT_H__
++#define __ASM_SMP_ALT_H__
++
++#include <linux/config.h>
++
++#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
++#define LOCK \
++ "6677: nop\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6677b\n" \
++ ".long 6678f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6678: .byte 1\n" \
++ ".byte 1\n" \
++ ".byte 0\n" \
++ ".byte 1\n" \
++ ".byte -1\n" \
++ "lock\n" \
++ "nop\n" \
++ ".previous\n"
++void prepare_for_smp(void);
++void unprepare_for_smp(void);
++#else
++#define LOCK "lock ; "
++#endif
++#else
++#define LOCK ""
++#endif
++
++#endif /* __ASM_SMP_ALT_H__ */
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/spinlock.h
./include/asm-i386/spinlock.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/spinlock.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/spinlock.h 2006-09-19 14:05:48.000000000 +0100
+@@ -6,6 +6,7 @@
+ #include <asm/page.h>
+ #include <linux/config.h>
+ #include <linux/compiler.h>
++#include <asm/smp_alt.h>
+
+ /*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+@@ -23,7 +24,8 @@
+
+ #define __raw_spin_lock_string \
+ "\n1:\t" \
+- "lock ; decb %0\n\t" \
++ LOCK \
++ "decb %0\n\t" \
+ "jns 3f\n" \
+ "2:\t" \
+ "rep;nop\n\t" \
+@@ -34,7 +36,8 @@
+
+ #define __raw_spin_lock_string_flags \
+ "\n1:\t" \
+- "lock ; decb %0\n\t" \
++ LOCK \
++ "decb %0\n\t" \
+ "jns 4f\n\t" \
+ "2:\t" \
+ "testl $0x200, %1\n\t" \
+@@ -65,10 +68,34 @@ static inline void __raw_spin_lock_flags
+ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+ {
+ char oldval;
++#ifdef CONFIG_SMP_ALTERNATIVES
+ __asm__ __volatile__(
+- "xchgb %b0,%1"
++ "1:movb %1,%b0\n"
++ "movb $0,%1\n"
++ "2:"
++ ".section __smp_alternatives,\"a\"\n"
++ ".long 1b\n"
++ ".long 3f\n"
++ ".previous\n"
++ ".section __smp_replacements,\"a\"\n"
++ "3: .byte 2b - 1b\n"
++ ".byte 5f-4f\n"
++ ".byte 0\n"
++ ".byte 6f-5f\n"
++ ".byte -1\n"
++ "4: xchgb %b0,%1\n"
++ "5: movb %1,%b0\n"
++ "movb $0,%1\n"
++ "6:\n"
++ ".previous\n"
+ :"=q" (oldval), "=m" (lock->slock)
+ :"0" (0) : "memory");
++#else
++ __asm__ __volatile__(
++ "xchgb %b0,%1\n"
++ :"=q" (oldval), "=m" (lock->slock)
++ :"0" (0) : "memory");
++#endif
+ return oldval > 0;
+ }
+
+@@ -178,12 +205,12 @@ static inline int __raw_write_trylock(ra
+
+ static inline void __raw_read_unlock(raw_rwlock_t *rw)
+ {
+- asm volatile("lock ; incl %0" :"=m" (rw->lock) : : "memory");
++ asm volatile(LOCK "incl %0" :"=m" (rw->lock) : : "memory");
+ }
+
+ static inline void __raw_write_unlock(raw_rwlock_t *rw)
+ {
+- asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ", %0"
++ asm volatile(LOCK "addl $" RW_LOCK_BIAS_STR ", %0"
+ : "=m" (rw->lock) : : "memory");
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/system.h
./include/asm-i386/system.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/system.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-i386/system.h 2006-09-19 14:05:48.000000000 +0100
+@@ -5,7 +5,7 @@
+ #include <linux/kernel.h>
+ #include <asm/segment.h>
+ #include <asm/cpufeature.h>
+-#include <linux/bitops.h> /* for LOCK_PREFIX */
++#include <asm/smp_alt.h>
+
+ #ifdef __KERNEL__
+
+@@ -271,19 +271,19 @@ static inline unsigned long __cmpxchg(vo
+ unsigned long prev;
+ switch (size) {
+ case 1:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
++ __asm__ __volatile__(LOCK "cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+@@ -336,7 +336,7 @@ static inline unsigned long long __cmpxc
+ unsigned long long new)
+ {
+ unsigned long long prev;
+- __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
++ __asm__ __volatile__(LOCK "cmpxchg8b %3"
+ : "=A"(prev)
+ : "b"((unsigned long)new),
+ "c"((unsigned long)(new >> 32)),
+@@ -503,11 +503,55 @@ struct alt_instr {
+ #endif
+
+ #ifdef CONFIG_SMP
++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE)
++#define smp_alt_mb(instr) \
++__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6667b\n" \
++ ".long 6673f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6673:.byte 6668b-6667b\n" \
++ ".byte 6670f-6669f\n" \
++ ".byte 6671f-6670f\n" \
++ ".byte 0\n" \
++ ".byte %c0\n" \
++ "6669:lock;addl $0,0(%%esp)\n" \
++ "6670:" instr "\n" \
++ "6671:\n" \
++ ".previous\n" \
++ : \
++ : "i" (X86_FEATURE_XMM2) \
++ : "memory")
++#define smp_rmb() smp_alt_mb("lfence")
++#define smp_mb() smp_alt_mb("mfence")
++#define set_mb(var, value) do { \
++unsigned long __set_mb_temp; \
++__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \
++ ".section __smp_alternatives,\"a\"\n" \
++ ".long 6667b\n" \
++ ".long 6673f\n" \
++ ".previous\n" \
++ ".section __smp_replacements,\"a\"\n" \
++ "6673: .byte 6668b-6667b\n" \
++ ".byte 6670f-6669f\n" \
++ ".byte 0\n" \
++ ".byte 6671f-6670f\n" \
++ ".byte -1\n" \
++ "6669: xchg %1, %0\n" \
++ "6670:movl %1, %0\n" \
++ "6671:\n" \
++ ".previous\n" \
++ : "=m" (var), "=r" (__set_mb_temp) \
++ : "1" (value) \
++ : "memory"); } while (0)
++#else
+ #define smp_mb() mb()
+ #define smp_rmb() rmb()
++#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
++#endif
+ #define smp_wmb() wmb()
+ #define smp_read_barrier_depends() read_barrier_depends()
+-#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
+ #else
+ #define smp_mb() barrier()
+ #define smp_rmb() barrier()
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/tpm_plugin_2.6.17.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/tpm_plugin_2.6.17.patch Tue Sep 19 14:26:47
2006 +0100
@@ -0,0 +1,1545 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c
./drivers/char/tpm/tpm_atmel.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_atmel.c 2006-09-19 14:05:52.000000000 +0100
+@@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip
+ return -EIO;
+
+ for (i = 0; i < 6; i++) {
+- status = ioread8(chip->vendor->iobase + 1);
++ status = ioread8(chip->vendor.iobase + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev, "error reading header\n");
+ return -EIO;
+ }
+- *buf++ = ioread8(chip->vendor->iobase);
++ *buf++ = ioread8(chip->vendor.iobase);
+ }
+
+ /* size of the data received */
+@@ -63,7 +63,7 @@ static int tpm_atml_recv(struct tpm_chip
+ dev_err(chip->dev,
+ "Recv size(%d) less than available space\n", size);
+ for (; i < size; i++) { /* clear the waiting data anyway */
+- status = ioread8(chip->vendor->iobase + 1);
++ status = ioread8(chip->vendor.iobase + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev, "error reading data\n");
+ return -EIO;
+@@ -74,16 +74,16 @@ static int tpm_atml_recv(struct tpm_chip
+
+ /* read all the data available */
+ for (; i < size; i++) {
+- status = ioread8(chip->vendor->iobase + 1);
++ status = ioread8(chip->vendor.iobase + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev, "error reading data\n");
+ return -EIO;
+ }
+- *buf++ = ioread8(chip->vendor->iobase);
++ *buf++ = ioread8(chip->vendor.iobase);
+ }
+
+ /* make sure data available is gone */
+- status = ioread8(chip->vendor->iobase + 1);
++ status = ioread8(chip->vendor.iobase + 1);
+
+ if (status & ATML_STATUS_DATA_AVAIL) {
+ dev_err(chip->dev, "data available is stuck\n");
+@@ -100,7 +100,7 @@ static int tpm_atml_send(struct tpm_chip
+ dev_dbg(chip->dev, "tpm_atml_send:\n");
+ for (i = 0; i < count; i++) {
+ dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
+- iowrite8(buf[i], chip->vendor->iobase);
++ iowrite8(buf[i], chip->vendor.iobase);
+ }
+
+ return count;
+@@ -108,12 +108,12 @@ static int tpm_atml_send(struct tpm_chip
+
+ static void tpm_atml_cancel(struct tpm_chip *chip)
+ {
+- iowrite8(ATML_STATUS_ABORT, chip->vendor->iobase + 1);
++ iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1);
+ }
+
+ static u8 tpm_atml_status(struct tpm_chip *chip)
+ {
+- return ioread8(chip->vendor->iobase + 1);
++ return ioread8(chip->vendor.iobase + 1);
+ }
+
+ static struct file_operations atmel_ops = {
+@@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] =
+
+ static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
+-static struct tpm_vendor_specific tpm_atmel = {
++static const struct tpm_vendor_specific tpm_atmel = {
+ .recv = tpm_atml_recv,
+ .send = tpm_atml_send,
+ .cancel = tpm_atml_cancel,
+@@ -159,10 +159,10 @@ static void atml_plat_remove(void)
+ struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
+ if (chip) {
+- if (chip->vendor->have_region)
+- atmel_release_region(chip->vendor->base,
+- chip->vendor->region_size);
+- atmel_put_base_addr(chip->vendor);
++ if (chip->vendor.have_region)
++ atmel_release_region(chip->vendor.base,
++ chip->vendor.region_size);
++ atmel_put_base_addr(chip->vendor.iobase);
+ tpm_remove_hardware(chip->dev);
+ platform_device_unregister(pdev);
+ }
+@@ -179,18 +179,22 @@ static struct device_driver atml_drv = {
+ static int __init init_atmel(void)
+ {
+ int rc = 0;
++ void __iomem *iobase = NULL;
++ int have_region, region_size;
++ unsigned long base;
++ struct tpm_chip *chip;
+
+ driver_register(&atml_drv);
+
+- if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) {
++ if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) {
+ rc = -ENODEV;
+ goto err_unreg_drv;
+ }
+
+- tpm_atmel.have_region =
++ have_region =
+ (atmel_request_region
+- (tpm_atmel.base, tpm_atmel.region_size,
+- "tpm_atmel0") == NULL) ? 0 : 1;
++ (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
++
+
+ if (IS_ERR
+ (pdev =
+@@ -199,17 +203,25 @@ static int __init init_atmel(void)
+ goto err_rel_reg;
+ }
+
+- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0)
++ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
++ rc = -ENODEV;
+ goto err_unreg_dev;
++ }
++
++ chip->vendor.iobase = iobase;
++ chip->vendor.base = base;
++ chip->vendor.have_region = have_region;
++ chip->vendor.region_size = region_size;
++
+ return 0;
+
+ err_unreg_dev:
+ platform_device_unregister(pdev);
+ err_rel_reg:
+- atmel_put_base_addr(&tpm_atmel);
+- if (tpm_atmel.have_region)
+- atmel_release_region(tpm_atmel.base,
+- tpm_atmel.region_size);
++ atmel_put_base_addr(iobase);
++ if (have_region)
++ atmel_release_region(base,
++ region_size);
+ err_unreg_drv:
+ driver_unregister(&atml_drv);
+ return rc;
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h
./drivers/char/tpm/tpm_atmel.h
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_atmel.h 2006-09-19 14:05:52.000000000 +0100
+@@ -28,13 +28,12 @@
+ #define atmel_request_region request_mem_region
+ #define atmel_release_region release_mem_region
+
+-static inline void atmel_put_base_addr(struct tpm_vendor_specific
+- *vendor)
++static inline void atmel_put_base_addr(void __iomem *iobase)
+ {
+- iounmap(vendor->iobase);
++ iounmap(iobase);
+ }
+
+-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor)
++static void __iomem * atmel_get_base_addr(unsigned long *base, int
*region_size)
+ {
+ struct device_node *dn;
+ unsigned long address, size;
+@@ -71,9 +70,9 @@ static void __iomem * atmel_get_base_add
+ else
+ size = reg[naddrc];
+
+- vendor->base = address;
+- vendor->region_size = size;
+- return ioremap(vendor->base, vendor->region_size);
++ *base = address;
++ *region_size = size;
++ return ioremap(*base, *region_size);
+ }
+ #else
+ #define atmel_getb(chip, offset) inb(chip->vendor->base + offset)
+@@ -106,14 +105,12 @@ static int atmel_verify_tpm11(void)
+ return 0;
+ }
+
+-static inline void atmel_put_base_addr(struct tpm_vendor_specific
+- *vendor)
++static inline void atmel_put_base_addr(void __iomem *iobase)
+ {
+ }
+
+ /* Determine where to talk to device */
+-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific
+- *vendor)
++static void __iomem * atmel_get_base_addr(unsigned long *base, int
*region_size)
+ {
+ int lo, hi;
+
+@@ -123,9 +120,9 @@ static void __iomem * atmel_get_base_add
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+- vendor->base = (hi << 8) | lo;
+- vendor->region_size = 2;
++ *base = (hi << 8) | lo;
++ *region_size = 2;
+
+- return ioport_map(vendor->base, vendor->region_size);
++ return ioport_map(*base, *region_size);
+ }
+ #endif
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c
./drivers/char/tpm/tpm_bios.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_bios.c 2006-09-19 14:05:52.000000000 +0100
+@@ -29,6 +29,11 @@
+ #define MAX_TEXT_EVENT 1000 /* Max event string length */
+ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
+
++enum bios_platform_class {
++ BIOS_CLIENT = 0x00,
++ BIOS_SERVER = 0x01,
++};
++
+ struct tpm_bios_log {
+ void *bios_event_log;
+ void *bios_event_log_end;
+@@ -36,9 +41,18 @@ struct tpm_bios_log {
+
+ struct acpi_tcpa {
+ struct acpi_table_header hdr;
+- u16 reserved;
+- u32 log_max_len __attribute__ ((packed));
+- u32 log_start_addr __attribute__ ((packed));
++ u16 platform_class;
++ union {
++ struct client_hdr {
++ u32 log_max_len __attribute__ ((packed));
++ u64 log_start_addr __attribute__ ((packed));
++ } client;
++ struct server_hdr {
++ u16 reserved;
++ u64 log_max_len __attribute__ ((packed));
++ u64 log_start_addr __attribute__ ((packed));
++ } server;
++ };
+ };
+
+ struct tcpa_event {
+@@ -91,6 +105,12 @@ static const char* tcpa_event_type_strin
+ "Non-Host Info"
+ };
+
++struct tcpa_pc_event {
++ u32 event_id;
++ u32 event_size;
++ u8 event_data[0];
++};
++
+ enum tcpa_pc_event_ids {
+ SMBIOS = 1,
+ BIS_CERT,
+@@ -100,14 +120,15 @@ enum tcpa_pc_event_ids {
+ NVRAM,
+ OPTION_ROM_EXEC,
+ OPTION_ROM_CONFIG,
+- OPTION_ROM_MICROCODE,
++ OPTION_ROM_MICROCODE = 10,
+ S_CRTM_VERSION,
+ S_CRTM_CONTENTS,
+ POST_CONTENTS,
++ HOST_TABLE_OF_DEVICES,
+ };
+
+ static const char* tcpa_pc_event_id_strings[] = {
+- ""
++ "",
+ "SMBIOS",
+ "BIS Certificate",
+ "POST BIOS ",
+@@ -116,10 +137,12 @@ static const char* tcpa_pc_event_id_stri
+ "NVRAM",
+ "Option ROM",
+ "Option ROM config",
+- "Option ROM microcode",
++ "",
++ "Option ROM microcode ",
+ "S-CRTM Version",
+- "S-CRTM Contents",
+- "S-CRTM POST Contents",
++ "S-CRTM Contents ",
++ "POST Contents ",
++ "Table of Devices",
+ };
+
+ /* returns pointer to start of pos. entry of tcg log */
+@@ -191,7 +214,7 @@ static int get_event_name(char *dest, st
+ const char *name = "";
+ char data[40] = "";
+ int i, n_len = 0, d_len = 0;
+- u32 event_id;
++ struct tcpa_pc_event *pc_event;
+
+ switch(event->event_type) {
+ case PREBOOT:
+@@ -220,31 +243,32 @@ static int get_event_name(char *dest, st
+ }
+ break;
+ case EVENT_TAG:
+- event_id = be32_to_cpu(*((u32 *)event_entry));
++ pc_event = (struct tcpa_pc_event *)event_entry;
+
+ /* ToDo Row data -> Base64 */
+
+- switch (event_id) {
++ switch (pc_event->event_id) {
+ case SMBIOS:
+ case BIS_CERT:
+ case CMOS:
+ case NVRAM:
+ case OPTION_ROM_EXEC:
+ case OPTION_ROM_CONFIG:
+- case OPTION_ROM_MICROCODE:
+ case S_CRTM_VERSION:
+- case S_CRTM_CONTENTS:
+- case POST_CONTENTS:
+- name = tcpa_pc_event_id_strings[event_id];
++ name = tcpa_pc_event_id_strings[pc_event->event_id];
+ n_len = strlen(name);
+ break;
++ /* hash data */
+ case POST_BIOS_ROM:
+ case ESCD:
+- name = tcpa_pc_event_id_strings[event_id];
++ case OPTION_ROM_MICROCODE:
++ case S_CRTM_CONTENTS:
++ case POST_CONTENTS:
++ name = tcpa_pc_event_id_strings[pc_event->event_id];
+ n_len = strlen(name);
+ for (i = 0; i < 20; i++)
+- d_len += sprintf(data, "%02x",
+- event_entry[8 + i]);
++ d_len += sprintf(&data[2*i], "%02x",
++ pc_event->event_data[i]);
+ break;
+ default:
+ break;
+@@ -260,52 +284,13 @@ static int get_event_name(char *dest, st
+
+ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
+ {
++ struct tcpa_event *event = v;
++ char *data = v;
++ int i;
+
+- char *eventname;
+- char data[4];
+- u32 help;
+- int i, len;
+- struct tcpa_event *event = (struct tcpa_event *) v;
+- unsigned char *event_entry =
+- (unsigned char *) (v + sizeof(struct tcpa_event));
+-
+- eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+- if (!eventname) {
+- printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+- __func__);
+- return -ENOMEM;
+- }
+-
+- /* 1st: PCR used is in little-endian format (4 bytes) */
+- help = le32_to_cpu(event->pcr_index);
+- memcpy(data, &help, 4);
+- for (i = 0; i < 4; i++)
+- seq_putc(m, data[i]);
+-
+- /* 2nd: SHA1 (20 bytes) */
+- for (i = 0; i < 20; i++)
+- seq_putc(m, event->pcr_value[i]);
+-
+- /* 3rd: event type identifier (4 bytes) */
+- help = le32_to_cpu(event->event_type);
+- memcpy(data, &help, 4);
+- for (i = 0; i < 4; i++)
++ for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
+ seq_putc(m, data[i]);
+
+- len = 0;
+-
+- len += get_event_name(eventname, event, event_entry);
+-
+- /* 4th: filename <= 255 + \'0' delimiter */
+- if (len > TCG_EVENT_NAME_LEN_MAX)
+- len = TCG_EVENT_NAME_LEN_MAX;
+-
+- for (i = 0; i < len; i++)
+- seq_putc(m, eventname[i]);
+-
+- /* 5th: delimiter */
+- seq_putc(m, '\0');
+-
+ return 0;
+ }
+
+@@ -353,6 +338,7 @@ static int tpm_ascii_bios_measurements_s
+ /* 4th: eventname <= max + \'0' delimiter */
+ seq_printf(m, " %s\n", eventname);
+
++ kfree(eventname);
+ return 0;
+ }
+
+@@ -376,6 +362,7 @@ static int read_log(struct tpm_bios_log
+ struct acpi_tcpa *buff;
+ acpi_status status;
+ struct acpi_table_header *virt;
++ u64 len, start;
+
+ if (log->bios_event_log != NULL) {
+ printk(KERN_ERR
+@@ -396,27 +383,37 @@ static int read_log(struct tpm_bios_log
+ return -EIO;
+ }
+
+- if (buff->log_max_len == 0) {
++ switch(buff->platform_class) {
++ case BIOS_SERVER:
++ len = buff->server.log_max_len;
++ start = buff->server.log_start_addr;
++ break;
++ case BIOS_CLIENT:
++ default:
++ len = buff->client.log_max_len;
++ start = buff->client.log_start_addr;
++ break;
++ }
++ if (!len) {
+ printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
+ return -EIO;
+ }
+
+ /* malloc EventLog space */
+- log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
++ log->bios_event_log = kmalloc(len, GFP_KERNEL);
+ if (!log->bios_event_log) {
+- printk
+- ("%s: ERROR - Not enough Memory for BIOS measurements\n",
+- __func__);
++ printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
++ __func__);
+ return -ENOMEM;
+ }
+
+- log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
++ log->bios_event_log_end = log->bios_event_log + len;
+
+- acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *)
&virt);
++ acpi_os_map_memory(start, len, (void *) &virt);
+
+- memcpy(log->bios_event_log, virt, buff->log_max_len);
++ memcpy(log->bios_event_log, virt, len);
+
+- acpi_os_unmap_memory(virt, buff->log_max_len);
++ acpi_os_unmap_memory(virt, len);
+ return 0;
+ }
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c
./drivers/char/tpm/tpm_infineon.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_infineon.c 2006-09-19 14:05:52.000000000 +0100
+@@ -15,6 +15,7 @@
+ * License.
+ */
+
++#include <linux/init.h>
+ #include <linux/pnp.h>
+ #include "tpm.h"
+
+@@ -104,7 +105,7 @@ static int empty_fifo(struct tpm_chip *c
+
+ if (clear_wrfifo) {
+ for (i = 0; i < 4096; i++) {
+- status = inb(chip->vendor->base + WRFIFO);
++ status = inb(chip->vendor.base + WRFIFO);
+ if (status == 0xff) {
+ if (check == 5)
+ break;
+@@ -124,8 +125,8 @@ static int empty_fifo(struct tpm_chip *c
+ */
+ i = 0;
+ do {
+- status = inb(chip->vendor->base + RDFIFO);
+- status = inb(chip->vendor->base + STAT);
++ status = inb(chip->vendor.base + RDFIFO);
++ status = inb(chip->vendor.base + STAT);
+ i++;
+ if (i == TPM_MAX_TRIES)
+ return -EIO;
+@@ -138,7 +139,7 @@ static int wait(struct tpm_chip *chip, i
+ int status;
+ int i;
+ for (i = 0; i < TPM_MAX_TRIES; i++) {
+- status = inb(chip->vendor->base + STAT);
++ status = inb(chip->vendor.base + STAT);
+ /* check the status-register if wait_for_bit is set */
+ if (status & 1 << wait_for_bit)
+ break;
+@@ -157,7 +158,7 @@ static int wait(struct tpm_chip *chip, i
+ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
+ {
+ wait(chip, STAT_XFE);
+- outb(sendbyte, chip->vendor->base + WRFIFO);
++ outb(sendbyte, chip->vendor.base + WRFIFO);
+ }
+
+ /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
+@@ -204,7 +205,7 @@ recv_begin:
+ ret = wait(chip, STAT_RDA);
+ if (ret)
+ return -EIO;
+- buf[i] = inb(chip->vendor->base + RDFIFO);
++ buf[i] = inb(chip->vendor.base + RDFIFO);
+ }
+
+ if (buf[0] != TPM_VL_VER) {
+@@ -219,7 +220,7 @@ recv_begin:
+
+ for (i = 0; i < size; i++) {
+ wait(chip, STAT_RDA);
+- buf[i] = inb(chip->vendor->base + RDFIFO);
++ buf[i] = inb(chip->vendor.base + RDFIFO);
+ }
+
+ if ((size == 0x6D00) && (buf[1] == 0x80)) {
+@@ -268,7 +269,7 @@ static int tpm_inf_send(struct tpm_chip
+ u8 count_high, count_low, count_4, count_3, count_2, count_1;
+
+ /* Disabling Reset, LP and IRQC */
+- outb(RESET_LP_IRQC_DISABLE, chip->vendor->base + CMD);
++ outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
+
+ ret = empty_fifo(chip, 1);
+ if (ret) {
+@@ -319,7 +320,7 @@ static void tpm_inf_cancel(struct tpm_ch
+
+ static u8 tpm_inf_status(struct tpm_chip *chip)
+ {
+- return inb(chip->vendor->base + STAT);
++ return inb(chip->vendor.base + STAT);
+ }
+
+ static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+@@ -346,7 +347,7 @@ static struct file_operations inf_ops =
+ .release = tpm_release,
+ };
+
+-static struct tpm_vendor_specific tpm_inf = {
++static const struct tpm_vendor_specific tpm_inf = {
+ .recv = tpm_inf_recv,
+ .send = tpm_inf_send,
+ .cancel = tpm_inf_cancel,
+@@ -375,6 +376,7 @@ static int __devinit tpm_inf_pnp_probe(s
+ int version[2];
+ int productid[2];
+ char chipname[20];
++ struct tpm_chip *chip;
+
+ /* read IO-ports through PnP */
+ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
+@@ -395,14 +397,13 @@ static int __devinit tpm_inf_pnp_probe(s
+ goto err_last;
+ }
+ /* publish my base address and request region */
+- tpm_inf.base = TPM_INF_BASE;
+ if (request_region
+- (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
++ (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
+ rc = -EINVAL;
+ goto err_last;
+ }
+- if (request_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN,
+- "tpm_infineon0") == NULL) {
++ if (request_region
++ (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
+ rc = -EINVAL;
+ goto err_last;
+ }
+@@ -442,9 +443,9 @@ static int __devinit tpm_inf_pnp_probe(s
+
+ /* configure TPM with IO-ports */
+ outb(IOLIMH, TPM_INF_ADDR);
+- outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA);
++ outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
+ outb(IOLIML, TPM_INF_ADDR);
+- outb((tpm_inf.base & 0xff), TPM_INF_DATA);
++ outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
+
+ /* control if IO-ports are set correctly */
+ outb(IOLIMH, TPM_INF_ADDR);
+@@ -452,10 +453,10 @@ static int __devinit tpm_inf_pnp_probe(s
+ outb(IOLIML, TPM_INF_ADDR);
+ iol = inb(TPM_INF_DATA);
+
+- if ((ioh << 8 | iol) != tpm_inf.base) {
++ if ((ioh << 8 | iol) != TPM_INF_BASE) {
+ dev_err(&dev->dev,
+- "Could not set IO-ports to 0x%lx\n",
+- tpm_inf.base);
++ "Could not set IO-ports to 0x%x\n",
++ TPM_INF_BASE);
+ rc = -EIO;
+ goto err_release_region;
+ }
+@@ -466,15 +467,15 @@ static int __devinit tpm_inf_pnp_probe(s
+ outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
+
+ /* disable RESET, LP and IRQC */
+- outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD);
++ outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
+
+ /* Finally, we're done, print some infos */
+ dev_info(&dev->dev, "TPM found: "
+ "config base 0x%x, "
+ "io base 0x%x, "
+- "chip version %02x%02x, "
+- "vendor id %x%x (Infineon), "
+- "product id %02x%02x"
++ "chip version 0x%02x%02x, "
++ "vendor id 0x%x%x (Infineon), "
++ "product id 0x%02x%02x"
+ "%s\n",
+ TPM_INF_ADDR,
+ TPM_INF_BASE,
+@@ -482,11 +483,10 @@ static int __devinit tpm_inf_pnp_probe(s
+ vendorid[0], vendorid[1],
+ productid[0], productid[1], chipname);
+
+- rc = tpm_register_hardware(&dev->dev, &tpm_inf);
+- if (rc < 0) {
+- rc = -ENODEV;
++ if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
+ goto err_release_region;
+ }
++ chip->vendor.base = TPM_INF_BASE;
+ return 0;
+ } else {
+ rc = -ENODEV;
+@@ -494,7 +494,7 @@ static int __devinit tpm_inf_pnp_probe(s
+ }
+
+ err_release_region:
+- release_region(tpm_inf.base, TPM_INF_PORT_LEN);
++ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
+ release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+
+ err_last:
+@@ -506,7 +506,8 @@ static __devexit void tpm_inf_pnp_remove
+ struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+ if (chip) {
+- release_region(chip->vendor->base, TPM_INF_PORT_LEN);
++ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
++ release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+ tpm_remove_hardware(chip->dev);
+ }
+ }
+@@ -520,7 +521,7 @@ static struct pnp_driver tpm_inf_pnp = {
+ },
+ .id_table = tpm_pnp_tbl,
+ .probe = tpm_inf_pnp_probe,
+- .remove = tpm_inf_pnp_remove,
++ .remove = __devexit_p(tpm_inf_pnp_remove),
+ };
+
+ static int __init init_inf(void)
+@@ -538,5 +539,5 @@ module_exit(cleanup_inf);
+
+ MODULE_AUTHOR("Marcel Selhorst <selhorst@xxxxxxxxxxxxx>");
+ MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT
1.2");
+-MODULE_VERSION("1.7");
++MODULE_VERSION("1.8");
+ MODULE_LICENSE("GPL");
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c
./drivers/char/tpm/tpm_nsc.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_nsc.c 2006-09-19 14:05:52.000000000 +0100
+@@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip
+ unsigned long stop;
+
+ /* status immediately available check */
+- *data = inb(chip->vendor->base + NSC_STATUS);
++ *data = inb(chip->vendor.base + NSC_STATUS);
+ if ((*data & mask) == val)
+ return 0;
+
+@@ -79,7 +79,7 @@ static int wait_for_stat(struct tpm_chip
+ stop = jiffies + 10 * HZ;
+ do {
+ msleep(TPM_TIMEOUT);
+- *data = inb(chip->vendor->base + 1);
++ *data = inb(chip->vendor.base + 1);
+ if ((*data & mask) == val)
+ return 0;
+ }
+@@ -94,9 +94,9 @@ static int nsc_wait_for_ready(struct tpm
+ unsigned long stop;
+
+ /* status immediately available check */
+- status = inb(chip->vendor->base + NSC_STATUS);
++ status = inb(chip->vendor.base + NSC_STATUS);
+ if (status & NSC_STATUS_OBF)
+- status = inb(chip->vendor->base + NSC_DATA);
++ status = inb(chip->vendor.base + NSC_DATA);
+ if (status & NSC_STATUS_RDY)
+ return 0;
+
+@@ -104,9 +104,9 @@ static int nsc_wait_for_ready(struct tpm
+ stop = jiffies + 100;
+ do {
+ msleep(TPM_TIMEOUT);
+- status = inb(chip->vendor->base + NSC_STATUS);
++ status = inb(chip->vendor.base + NSC_STATUS);
+ if (status & NSC_STATUS_OBF)
+- status = inb(chip->vendor->base + NSC_DATA);
++ status = inb(chip->vendor.base + NSC_DATA);
+ if (status & NSC_STATUS_RDY)
+ return 0;
+ }
+@@ -132,7 +132,7 @@ static int tpm_nsc_recv(struct tpm_chip
+ return -EIO;
+ }
+ if ((data =
+- inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
++ inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
+ dev_err(chip->dev, "not in normal mode (0x%x)\n",
+ data);
+ return -EIO;
+@@ -148,7 +148,7 @@ static int tpm_nsc_recv(struct tpm_chip
+ }
+ if (data & NSC_STATUS_F0)
+ break;
+- *p = inb(chip->vendor->base + NSC_DATA);
++ *p = inb(chip->vendor.base + NSC_DATA);
+ }
+
+ if ((data & NSC_STATUS_F0) == 0 &&
+@@ -156,7 +156,7 @@ static int tpm_nsc_recv(struct tpm_chip
+ dev_err(chip->dev, "F0 not set\n");
+ return -EIO;
+ }
+- if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
++ if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
+ dev_err(chip->dev,
+ "expected end of command(0x%x)\n", data);
+ return -EIO;
+@@ -182,7 +182,7 @@ static int tpm_nsc_send(struct tpm_chip
+ * fix it. Not sure why this is needed, we followed the flow
+ * chart in the manual to the letter.
+ */
+- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
++ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND);
+
+ if (nsc_wait_for_ready(chip) != 0)
+ return -EIO;
+@@ -192,7 +192,7 @@ static int tpm_nsc_send(struct tpm_chip
+ return -EIO;
+ }
+
+- outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
++ outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
+ if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
+ dev_err(chip->dev, "IBR timeout\n");
+ return -EIO;
+@@ -204,26 +204,26 @@ static int tpm_nsc_send(struct tpm_chip
+ "IBF timeout (while writing data)\n");
+ return -EIO;
+ }
+- outb(buf[i], chip->vendor->base + NSC_DATA);
++ outb(buf[i], chip->vendor.base + NSC_DATA);
+ }
+
+ if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+ dev_err(chip->dev, "IBF timeout\n");
+ return -EIO;
+ }
+- outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
++ outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
+
+ return count;
+ }
+
+ static void tpm_nsc_cancel(struct tpm_chip *chip)
+ {
+- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
++ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND);
+ }
+
+ static u8 tpm_nsc_status(struct tpm_chip *chip)
+ {
+- return inb(chip->vendor->base + NSC_STATUS);
++ return inb(chip->vendor.base + NSC_STATUS);
+ }
+
+ static struct file_operations nsc_ops = {
+@@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] =
+
+ static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
+-static struct tpm_vendor_specific tpm_nsc = {
++static const struct tpm_vendor_specific tpm_nsc = {
+ .recv = tpm_nsc_recv,
+ .send = tpm_nsc_send,
+ .cancel = tpm_nsc_cancel,
+@@ -268,7 +268,7 @@ static void __devexit tpm_nsc_remove(str
+ {
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if ( chip ) {
+- release_region(chip->vendor->base, 2);
++ release_region(chip->vendor.base, 2);
+ tpm_remove_hardware(chip->dev);
+ }
+ }
+@@ -286,7 +286,8 @@ static int __init init_nsc(void)
+ int rc = 0;
+ int lo, hi;
+ int nscAddrBase = TPM_ADDR;
+-
++ struct tpm_chip *chip;
++ unsigned long base;
+
+ /* verify that it is a National part (SID) */
+ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+@@ -300,7 +301,7 @@ static int __init init_nsc(void)
+
+ hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+ lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+- tpm_nsc.base = (hi<<8) | lo;
++ base = (hi<<8) | lo;
+
+ /* enable the DPM module */
+ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
+@@ -320,13 +321,15 @@ static int __init init_nsc(void)
+ if ((rc = platform_device_register(pdev)) < 0)
+ goto err_free_dev;
+
+- if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) {
++ if (request_region(base, 2, "tpm_nsc0") == NULL ) {
+ rc = -EBUSY;
+ goto err_unreg_dev;
+ }
+
+- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0)
++ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
++ rc = -ENODEV;
+ goto err_rel_reg;
++ }
+
+ dev_dbg(&pdev->dev, "NSC TPM detected\n");
+ dev_dbg(&pdev->dev,
+@@ -361,10 +364,12 @@ static int __init init_nsc(void)
+ "NSC TPM revision %d\n",
+ tpm_read_index(nscAddrBase, 0x27) & 0x1F);
+
++ chip->vendor.base = base;
++
+ return 0;
+
+ err_rel_reg:
+- release_region(tpm_nsc.base, 2);
++ release_region(base, 2);
+ err_unreg_dev:
+ platform_device_unregister(pdev);
+ err_free_dev:
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c
./drivers/char/tpm/tpm_tis.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c 1970-01-01
01:00:00.000000000 +0100
++++ ./drivers/char/tpm/tpm_tis.c 2006-09-19 14:05:52.000000000 +0100
+@@ -0,0 +1,665 @@
++/*
++ * Copyright (C) 2005, 2006 IBM Corporation
++ *
++ * Authors:
++ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
++ * Kylene Hall <kjhall@xxxxxxxxxx>
++ *
++ * Device driver for TCG/TCPA TPM (trusted platform module).
++ * Specifications at www.trustedcomputinggroup.org
++ *
++ * This device driver implements the TPM interface as defined in
++ * the TCG TPM Interface Spec version 1.2, revision 1.0.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation, version 2 of the
++ * License.
++ */
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/pnp.h>
++#include <linux/interrupt.h>
++#include <linux/wait.h>
++#include "tpm.h"
++
++#define TPM_HEADER_SIZE 10
++
++enum tis_access {
++ TPM_ACCESS_VALID = 0x80,
++ TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
++ TPM_ACCESS_REQUEST_PENDING = 0x04,
++ TPM_ACCESS_REQUEST_USE = 0x02,
++};
++
++enum tis_status {
++ TPM_STS_VALID = 0x80,
++ TPM_STS_COMMAND_READY = 0x40,
++ TPM_STS_GO = 0x20,
++ TPM_STS_DATA_AVAIL = 0x10,
++ TPM_STS_DATA_EXPECT = 0x08,
++};
++
++enum tis_int_flags {
++ TPM_GLOBAL_INT_ENABLE = 0x80000000,
++ TPM_INTF_BURST_COUNT_STATIC = 0x100,
++ TPM_INTF_CMD_READY_INT = 0x080,
++ TPM_INTF_INT_EDGE_FALLING = 0x040,
++ TPM_INTF_INT_EDGE_RISING = 0x020,
++ TPM_INTF_INT_LEVEL_LOW = 0x010,
++ TPM_INTF_INT_LEVEL_HIGH = 0x008,
++ TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
++ TPM_INTF_STS_VALID_INT = 0x002,
++ TPM_INTF_DATA_AVAIL_INT = 0x001,
++};
++
++enum tis_defaults {
++ TIS_MEM_BASE = 0xFED40000,
++ TIS_MEM_LEN = 0x5000,
++ TIS_SHORT_TIMEOUT = 750, /* ms */
++ TIS_LONG_TIMEOUT = 2000, /* 2 sec */
++};
++
++#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
++#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
++#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
++#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
++#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
++#define TPM_STS(l) (0x0018 | ((l) << 12))
++#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
++
++#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
++#define TPM_RID(l) (0x0F04 | ((l) << 12))
++
++static LIST_HEAD(tis_chips);
++static DEFINE_SPINLOCK(tis_lock);
++
++static int check_locality(struct tpm_chip *chip, int l)
++{
++ if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
++ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
++ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
++ return chip->vendor.locality = l;
++
++ return -1;
++}
++
++static void release_locality(struct tpm_chip *chip, int l, int force)
++{
++ if (force || (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
++ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
++ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))
++ iowrite8(TPM_ACCESS_ACTIVE_LOCALITY,
++ chip->vendor.iobase + TPM_ACCESS(l));
++}
++
++static int request_locality(struct tpm_chip *chip, int l)
++{
++ unsigned long stop;
++ long rc;
++
++ if (check_locality(chip, l) >= 0)
++ return l;
++
++ iowrite8(TPM_ACCESS_REQUEST_USE,
++ chip->vendor.iobase + TPM_ACCESS(l));
++
++ if (chip->vendor.irq) {
++ rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
++ (check_locality
++ (chip, l) >= 0),
++ chip->vendor.timeout_a);
++ if (rc > 0)
++ return l;
++
++ } else {
++ /* wait for burstcount */
++ stop = jiffies + chip->vendor.timeout_a;
++ do {
++ if (check_locality(chip, l) >= 0)
++ return l;
++ msleep(TPM_TIMEOUT);
++ }
++ while (time_before(jiffies, stop));
++ }
++ return -1;
++}
++
++static u8 tpm_tis_status(struct tpm_chip *chip)
++{
++ return ioread8(chip->vendor.iobase +
++ TPM_STS(chip->vendor.locality));
++}
++
++static void tpm_tis_ready(struct tpm_chip *chip)
++{
++ /* this causes the current command to be aborted */
++ iowrite8(TPM_STS_COMMAND_READY,
++ chip->vendor.iobase + TPM_STS(chip->vendor.locality));
++}
++
++static int get_burstcount(struct tpm_chip *chip)
++{
++ unsigned long stop;
++ int burstcnt;
++
++ /* wait for burstcount */
++ /* which timeout value, spec has 2 answers (c & d) */
++ stop = jiffies + chip->vendor.timeout_d;
++ do {
++ burstcnt = ioread8(chip->vendor.iobase +
++ TPM_STS(chip->vendor.locality) + 1);
++ burstcnt += ioread8(chip->vendor.iobase +
++ TPM_STS(chip->vendor.locality) +
++ 2) << 8;
++ if (burstcnt)
++ return burstcnt;
++ msleep(TPM_TIMEOUT);
++ } while (time_before(jiffies, stop));
++ return -EBUSY;
++}
++
++static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long
timeout,
++ wait_queue_head_t *queue)
++{
++ unsigned long stop;
++ long rc;
++ u8 status;
++
++ /* check current status */
++ status = tpm_tis_status(chip);
++ if ((status & mask) == mask)
++ return 0;
++
++ if (chip->vendor.irq) {
++ rc = wait_event_interruptible_timeout(*queue,
++ ((tpm_tis_status
++ (chip) & mask) ==
++ mask), timeout);
++ if (rc > 0)
++ return 0;
++ } else {
++ stop = jiffies + timeout;
++ do {
++ msleep(TPM_TIMEOUT);
++ status = tpm_tis_status(chip);
++ if ((status & mask) == mask)
++ return 0;
++ } while (time_before(jiffies, stop));
++ }
++ return -ETIME;
++}
++
++static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
++{
++ int size = 0, burstcnt;
++ while (size < count &&
++ wait_for_stat(chip,
++ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
++ chip->vendor.timeout_c,
++ &chip->vendor.read_queue)
++ == 0) {
++ burstcnt = get_burstcount(chip);
++ for (; burstcnt > 0 && size < count; burstcnt--)
++ buf[size++] = ioread8(chip->vendor.iobase +
++ TPM_DATA_FIFO(chip->vendor.
++ locality));
++ }
++ return size;
++}
++
++static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
++{
++ int size = 0;
++ int expected, status;
++
++ if (count < TPM_HEADER_SIZE) {
++ size = -EIO;
++ goto out;
++ }
++
++ /* read first 10 bytes, including tag, paramsize, and result */
++ if ((size =
++ recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
++ dev_err(chip->dev, "Unable to read header\n");
++ goto out;
++ }
++
++ expected = be32_to_cpu(*(__be32 *) (buf + 2));
++ if (expected > count) {
++ size = -EIO;
++ goto out;
++ }
++
++ if ((size +=
++ recv_data(chip, &buf[TPM_HEADER_SIZE],
++ expected - TPM_HEADER_SIZE)) < expected) {
++ dev_err(chip->dev, "Unable to read remainder of result\n");
++ size = -ETIME;
++ goto out;
++ }
++
++ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
++ &chip->vendor.int_queue);
++ status = tpm_tis_status(chip);
++ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
++ dev_err(chip->dev, "Error left over data\n");
++ size = -EIO;
++ goto out;
++ }
++
++out:
++ tpm_tis_ready(chip);
++ release_locality(chip, chip->vendor.locality, 0);
++ return size;
++}
++
++/*
++ * If interrupts are used (signaled by an irq set in the vendor structure)
++ * tpm.c can skip polling for the data to be available as the interrupt is
++ * waited for here
++ */
++static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
++{
++ int rc, status, burstcnt;
++ size_t count = 0;
++ u32 ordinal;
++
++ if (request_locality(chip, 0) < 0)
++ return -EBUSY;
++
++ status = tpm_tis_status(chip);
++ if ((status & TPM_STS_COMMAND_READY) == 0) {
++ tpm_tis_ready(chip);
++ if (wait_for_stat
++ (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
++ &chip->vendor.int_queue) < 0) {
++ rc = -ETIME;
++ goto out_err;
++ }
++ }
++
++ while (count < len - 1) {
++ burstcnt = get_burstcount(chip);
++ for (; burstcnt > 0 && count < len - 1; burstcnt--) {
++ iowrite8(buf[count], chip->vendor.iobase +
++ TPM_DATA_FIFO(chip->vendor.locality));
++ count++;
++ }
++
++ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
++ &chip->vendor.int_queue);
++ status = tpm_tis_status(chip);
++ if ((status & TPM_STS_DATA_EXPECT) == 0) {
++ rc = -EIO;
++ goto out_err;
++ }
++ }
++
++ /* write last byte */
++ iowrite8(buf[count],
++ chip->vendor.iobase +
++ TPM_DATA_FIFO(chip->vendor.locality));
++ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
++ &chip->vendor.int_queue);
++ status = tpm_tis_status(chip);
++ if ((status & TPM_STS_DATA_EXPECT) != 0) {
++ rc = -EIO;
++ goto out_err;
++ }
++
++ /* go and do it */
++ iowrite8(TPM_STS_GO,
++ chip->vendor.iobase + TPM_STS(chip->vendor.locality));
++
++ if (chip->vendor.irq) {
++ ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
++ if (wait_for_stat
++ (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
++ tpm_calc_ordinal_duration(chip, ordinal),
++ &chip->vendor.read_queue) < 0) {
++ rc = -ETIME;
++ goto out_err;
++ }
++ }
++ return len;
++out_err:
++ tpm_tis_ready(chip);
++ release_locality(chip, chip->vendor.locality, 0);
++ return rc;
++}
++
++static struct file_operations tis_ops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .open = tpm_open,
++ .read = tpm_read,
++ .write = tpm_write,
++ .release = tpm_release,
++};
++
++static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
++static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
++static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
++static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
++static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
++static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
++ NULL);
++static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
++static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
++
++static struct attribute *tis_attrs[] = {
++ &dev_attr_pubek.attr,
++ &dev_attr_pcrs.attr,
++ &dev_attr_enabled.attr,
++ &dev_attr_active.attr,
++ &dev_attr_owned.attr,
++ &dev_attr_temp_deactivated.attr,
++ &dev_attr_caps.attr,
++ &dev_attr_cancel.attr, NULL,
++};
++
++static struct attribute_group tis_attr_grp = {
++ .attrs = tis_attrs
++};
++
++static struct tpm_vendor_specific tpm_tis = {
++ .status = tpm_tis_status,
++ .recv = tpm_tis_recv,
++ .send = tpm_tis_send,
++ .cancel = tpm_tis_ready,
++ .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
++ .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
++ .req_canceled = TPM_STS_COMMAND_READY,
++ .attr_group = &tis_attr_grp,
++ .miscdev = {
++ .fops = &tis_ops,},
++};
++
++static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
++ u32 interrupt;
++
++ interrupt = ioread32(chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++
++ if (interrupt == 0)
++ return IRQ_NONE;
++
++ chip->vendor.irq = irq;
++
++ /* Clear interrupts handled with TPM_EOI */
++ iowrite32(interrupt,
++ chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs
*regs)
++{
++ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
++ u32 interrupt;
++ int i;
++
++ interrupt = ioread32(chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++
++ if (interrupt == 0)
++ return IRQ_NONE;
++
++ if (interrupt & TPM_INTF_DATA_AVAIL_INT)
++ wake_up_interruptible(&chip->vendor.read_queue);
++ if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
++ for (i = 0; i < 5; i++)
++ if (check_locality(chip, i) >= 0)
++ break;
++ if (interrupt &
++ (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
++ TPM_INTF_CMD_READY_INT))
++ wake_up_interruptible(&chip->vendor.int_queue);
++
++ /* Clear interrupts handled with TPM_EOI */
++ iowrite32(interrupt,
++ chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++ return IRQ_HANDLED;
++}
++
++static int interrupts = 1;
++module_param(interrupts, bool, 0444);
++MODULE_PARM_DESC(interrupts, "Enable interrupts");
++
++static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
++ const struct pnp_device_id *pnp_id)
++{
++ u32 vendor, intfcaps, intmask;
++ int rc, i;
++ unsigned long start, len;
++ struct tpm_chip *chip;
++
++ start = pnp_mem_start(pnp_dev, 0);
++ len = pnp_mem_len(pnp_dev, 0);
++
++ if (!start)
++ start = TIS_MEM_BASE;
++ if (!len)
++ len = TIS_MEM_LEN;
++
++ if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
++ return -ENODEV;
++
++ chip->vendor.iobase = ioremap(start, len);
++ if (!chip->vendor.iobase) {
++ rc = -EIO;
++ goto out_err;
++ }
++
++ vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
++
++ /* Default timeouts */
++ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++ chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
++ chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++ chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
++
++ dev_info(&pnp_dev->dev,
++ "1.2 TPM (device-id 0x%X, rev-id %d)\n",
++ vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
++
++ /* Figure out the capabilities */
++ intfcaps =
++ ioread32(chip->vendor.iobase +
++ TPM_INTF_CAPS(chip->vendor.locality));
++ dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
++ intfcaps);
++ if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
++ dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
++ if (intfcaps & TPM_INTF_CMD_READY_INT)
++ dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
++ if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
++ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
++ if (intfcaps & TPM_INTF_INT_EDGE_RISING)
++ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
++ if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
++ dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
++ if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
++ dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
++ if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
++ dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
++ if (intfcaps & TPM_INTF_STS_VALID_INT)
++ dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
++ if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
++ dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
++
++ if (request_locality(chip, 0) != 0) {
++ rc = -ENODEV;
++ goto out_err;
++ }
++
++ /* INTERRUPT Setup */
++ init_waitqueue_head(&chip->vendor.read_queue);
++ init_waitqueue_head(&chip->vendor.int_queue);
++
++ intmask =
++ ioread32(chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++
++ intmask |= TPM_INTF_CMD_READY_INT
++ | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
++ | TPM_INTF_STS_VALID_INT;
++
++ iowrite32(intmask,
++ chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++ if (interrupts) {
++ chip->vendor.irq =
++ ioread8(chip->vendor.iobase +
++ TPM_INT_VECTOR(chip->vendor.locality));
++
++ for (i = 3; i < 16 && chip->vendor.irq == 0; i++) {
++ iowrite8(i, chip->vendor.iobase +
++ TPM_INT_VECTOR(chip->vendor.locality));
++ if (request_irq
++ (i, tis_int_probe, SA_SHIRQ,
++ chip->vendor.miscdev.name, chip) != 0) {
++ dev_info(chip->dev,
++ "Unable to request irq: %d for
probe\n",
++ i);
++ continue;
++ }
++
++ /* Clear all existing */
++ iowrite32(ioread32
++ (chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality)),
++ chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++
++ /* Turn on */
++ iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
++ chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++
++ /* Generate Interrupts */
++ tpm_gen_interrupt(chip);
++
++ /* Turn off */
++ iowrite32(intmask,
++ chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++ free_irq(i, chip);
++ }
++ }
++ if (chip->vendor.irq) {
++ iowrite8(chip->vendor.irq,
++ chip->vendor.iobase +
++ TPM_INT_VECTOR(chip->vendor.locality));
++ if (request_irq
++ (chip->vendor.irq, tis_int_handler, SA_SHIRQ,
++ chip->vendor.miscdev.name, chip) != 0) {
++ dev_info(chip->dev,
++ "Unable to request irq: %d for use\n",
++ chip->vendor.irq);
++ chip->vendor.irq = 0;
++ } else {
++ /* Clear all existing */
++ iowrite32(ioread32
++ (chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality)),
++ chip->vendor.iobase +
++ TPM_INT_STATUS(chip->vendor.locality));
++
++ /* Turn on */
++ iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
++ chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++ }
++ }
++
++ INIT_LIST_HEAD(&chip->vendor.list);
++ spin_lock(&tis_lock);
++ list_add(&chip->vendor.list, &tis_chips);
++ spin_unlock(&tis_lock);
++
++ tpm_get_timeouts(chip);
++ tpm_continue_selftest(chip);
++
++ return 0;
++out_err:
++ if (chip->vendor.iobase)
++ iounmap(chip->vendor.iobase);
++ tpm_remove_hardware(chip->dev);
++ return rc;
++}
++
++static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
++{
++ return tpm_pm_suspend(&dev->dev, msg);
++}
++
++static int tpm_tis_pnp_resume(struct pnp_dev *dev)
++{
++ return tpm_pm_resume(&dev->dev);
++}
++
++static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
++ {"PNP0C31", 0}, /* TPM */
++ {"ATM1200", 0}, /* Atmel */
++ {"IFX0102", 0}, /* Infineon */
++ {"BCM0101", 0}, /* Broadcom */
++ {"NSC1200", 0}, /* National */
++ /* Add new here */
++ {"", 0}, /* User Specified */
++ {"", 0} /* Terminator */
++};
++
++static struct pnp_driver tis_pnp_driver = {
++ .name = "tpm_tis",
++ .id_table = tpm_pnp_tbl,
++ .probe = tpm_tis_pnp_init,
++ .suspend = tpm_tis_pnp_suspend,
++ .resume = tpm_tis_pnp_resume,
++};
++
++#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
++module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
++ sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
++MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
++
++static int __init init_tis(void)
++{
++ return pnp_register_driver(&tis_pnp_driver);
++}
++
++static void __exit cleanup_tis(void)
++{
++ struct tpm_vendor_specific *i, *j;
++ struct tpm_chip *chip;
++ spin_lock(&tis_lock);
++ list_for_each_entry_safe(i, j, &tis_chips, list) {
++ chip = to_tpm_chip(i);
++ iowrite32(~TPM_GLOBAL_INT_ENABLE &
++ ioread32(chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.
++ locality)),
++ chip->vendor.iobase +
++ TPM_INT_ENABLE(chip->vendor.locality));
++ release_locality(chip, chip->vendor.locality, 1);
++ if (chip->vendor.irq)
++ free_irq(chip->vendor.irq, chip);
++ iounmap(i->iobase);
++ list_del(&i->list);
++ tpm_remove_hardware(chip->dev);
++ }
++ spin_unlock(&tis_lock);
++ pnp_unregister_driver(&tis_pnp_driver);
++}
++
++module_init(init_tis);
++module_exit(cleanup_tis);
++MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
++MODULE_DESCRIPTION("TPM Driver");
++MODULE_VERSION("2.0");
++MODULE_LICENSE("GPL");
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/x86-elfnote-as-preprocessor-macro.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/x86-elfnote-as-preprocessor-macro.patch Tue Sep
19 14:26:47 2006 +0100
@@ -0,0 +1,43 @@
+diff -pruN ../orig-linux-2.6.16.29/include/linux/elfnote.h
./include/linux/elfnote.h
+--- ../orig-linux-2.6.16.29/include/linux/elfnote.h 2006-09-19
14:06:10.000000000 +0100
++++ ./include/linux/elfnote.h 2006-09-19 14:06:20.000000000 +0100
+@@ -31,22 +31,24 @@
+ /*
+ * Generate a structure with the same shape as Elf{32,64}_Nhdr (which
+ * turn out to be the same size and shape), followed by the name and
+- * desc data with appropriate padding. The 'desc' argument includes
+- * the assembler pseudo op defining the type of the data: .asciz
+- * "hello, world"
++ * desc data with appropriate padding. The 'desctype' argument is the
++ * assembler pseudo op defining the type of the data e.g. .asciz while
++ * 'descdata' is the data itself e.g. "hello, world".
++ *
++ * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
++ * ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
+ */
+-.macro ELFNOTE name type desc:vararg
+-.pushsection ".note.\name"
+- .align 4
+- .long 2f - 1f /* namesz */
+- .long 4f - 3f /* descsz */
+- .long \type
+-1:.asciz "\name"
+-2:.align 4
+-3:\desc
+-4:.align 4
+-.popsection
+-.endm
++#define ELFNOTE(name, type, desctype, descdata) \
++.pushsection .note.name ; \
++ .align 4 ; \
++ .long 2f - 1f /* namesz */ ; \
++ .long 4f - 3f /* descsz */ ; \
++ .long type ; \
++1:.asciz "name" ; \
++2:.align 4 ; \
++3:desctype descdata ; \
++4:.align 4 ; \
++.popsection ;
+ #else /* !__ASSEMBLER__ */
+ #include <linux/elf.h>
+ /*
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/x86-increase-interrupt-vector-range.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/x86-increase-interrupt-vector-range.patch Tue Sep
19 14:26:47 2006 +0100
@@ -0,0 +1,89 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S
./arch/i386/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S 2006-09-19
14:05:44.000000000 +0100
++++ ./arch/i386/kernel/entry.S 2006-09-19 14:05:56.000000000 +0100
+@@ -406,7 +406,7 @@ vector=0
+ ENTRY(irq_entries_start)
+ .rept NR_IRQS
+ ALIGN
+-1: pushl $vector-256
++1: pushl $~(vector)
+ jmp common_interrupt
+ .data
+ .long 1b
+@@ -423,7 +423,7 @@ common_interrupt:
+
+ #define BUILD_INTERRUPT(name, nr) \
+ ENTRY(name) \
+- pushl $nr-256; \
++ pushl $~(nr); \
+ SAVE_ALL \
+ movl %esp,%eax; \
+ call smp_/**/name; \
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/irq.c
./arch/i386/kernel/irq.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/irq.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/i386/kernel/irq.c 2006-09-19 14:05:56.000000000 +0100
+@@ -53,8 +53,8 @@ static union irq_ctx *softirq_ctx[NR_CPU
+ */
+ fastcall unsigned int do_IRQ(struct pt_regs *regs)
+ {
+- /* high bits used in ret_from_ code */
+- int irq = regs->orig_eax & 0xff;
++ /* high bit used in ret_from_ code */
++ int irq = ~regs->orig_eax;
+ #ifdef CONFIG_4KSTACKS
+ union irq_ctx *curctx, *irqctx;
+ u32 *isp;
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/entry.S
./arch/x86_64/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/entry.S 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/entry.S 2006-09-19 14:05:56.000000000 +0100
+@@ -596,7 +596,7 @@ retint_kernel:
+ */
+ .macro apicinterrupt num,func
+ INTR_FRAME
+- pushq $\num-256
++ pushq $~(\num)
+ CFI_ADJUST_CFA_OFFSET 8
+ interrupt \func
+ jmp ret_from_intr
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/irq.c
./arch/x86_64/kernel/irq.c
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/irq.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/irq.c 2006-09-19 14:05:56.000000000 +0100
+@@ -96,8 +96,8 @@ skip:
+ */
+ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
+ {
+- /* high bits used in ret_from_ code */
+- unsigned irq = regs->orig_rax & 0xff;
++ /* high bit used in ret_from_ code */
++ unsigned irq = ~regs->orig_rax;
+
+ exit_idle();
+ irq_enter();
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/smp.c
./arch/x86_64/kernel/smp.c
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/smp.c 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/smp.c 2006-09-19 14:05:56.000000000 +0100
+@@ -135,10 +135,10 @@ asmlinkage void smp_invalidate_interrupt
+
+ cpu = smp_processor_id();
+ /*
+- * orig_rax contains the interrupt vector - 256.
++ * orig_rax contains the negated interrupt vector.
+ * Use that to determine where the sender put the data.
+ */
+- sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START;
++ sender = ~regs->orig_rax - INVALIDATE_TLB_VECTOR_START;
+ f = &per_cpu(flush_state, sender);
+
+ if (!cpu_isset(cpu, f->flush_cpumask))
+diff -pruN ../orig-linux-2.6.16.29/include/asm-x86_64/hw_irq.h
./include/asm-x86_64/hw_irq.h
+--- ../orig-linux-2.6.16.29/include/asm-x86_64/hw_irq.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-x86_64/hw_irq.h 2006-09-19 14:05:56.000000000 +0100
+@@ -127,7 +127,7 @@ asmlinkage void IRQ_NAME(nr); \
+ __asm__( \
+ "\n.p2align\n" \
+ "IRQ" #nr "_interrupt:\n\t" \
+- "push $" #nr "-256 ; " \
++ "push $~(" #nr ") ; " \
+ "jmp common_interrupt");
+
+ #if defined(CONFIG_X86_IO_APIC)
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++
b/patches/linux-2.6.16.29/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,143 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S
./arch/i386/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S 2006-09-19
14:05:48.000000000 +0100
++++ ./arch/i386/kernel/vmlinux.lds.S 2006-09-19 14:06:10.000000000 +0100
+@@ -12,6 +12,12 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386"
+ OUTPUT_ARCH(i386)
+ ENTRY(phys_startup_32)
+ jiffies = jiffies_64;
++
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __KERNEL_START;
+@@ -25,7 +31,7 @@ SECTIONS
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+
+ _etext = .; /* End of text section */
+
+@@ -47,7 +53,7 @@ SECTIONS
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ . = ALIGN(4096);
+ __nosave_begin = .;
+@@ -154,4 +160,6 @@ SECTIONS
+ STABS_DEBUG
+
+ DWARF_DEBUG
++
++ NOTES
+ }
+diff -pruN ../orig-linux-2.6.16.29/include/asm-generic/vmlinux.lds.h
./include/asm-generic/vmlinux.lds.h
+--- ../orig-linux-2.6.16.29/include/asm-generic/vmlinux.lds.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/asm-generic/vmlinux.lds.h 2006-09-19 14:06:10.000000000
+0100
+@@ -152,3 +152,6 @@
+ .stab.index 0 : { *(.stab.index) } \
+ .stab.indexstr 0 : { *(.stab.indexstr) } \
+ .comment 0 : { *(.comment) }
++
++#define NOTES \
++ .notes : { *(.note.*) } :note
+diff -pruN ../orig-linux-2.6.16.29/include/linux/elfnote.h
./include/linux/elfnote.h
+--- ../orig-linux-2.6.16.29/include/linux/elfnote.h 1970-01-01
01:00:00.000000000 +0100
++++ ./include/linux/elfnote.h 2006-09-19 14:06:10.000000000 +0100
+@@ -0,0 +1,88 @@
++#ifndef _LINUX_ELFNOTE_H
++#define _LINUX_ELFNOTE_H
++/*
++ * Helper macros to generate ELF Note structures, which are put into a
++ * PT_NOTE segment of the final vmlinux image. These are useful for
++ * including name-value pairs of metadata into the kernel binary (or
++ * modules?) for use by external programs.
++ *
++ * Each note has three parts: a name, a type and a desc. The name is
++ * intended to distinguish the note's originator, so it would be a
++ * company, project, subsystem, etc; it must be in a suitable form for
++ * use in a section name. The type is an integer which is used to tag
++ * the data, and is considered to be within the "name" namespace (so
++ * "FooCo"'s type 42 is distinct from "BarProj"'s type 42). The
++ * "desc" field is the actual data. There are no constraints on the
++ * desc field's contents, though typically they're fairly small.
++ *
++ * All notes from a given NAME are put into a section named
++ * .note.NAME. When the kernel image is finally linked, all the notes
++ * are packed into a single .notes section, which is mapped into the
++ * PT_NOTE segment. Because notes for a given name are grouped into
++ * the same section, they'll all be adjacent the output file.
++ *
++ * This file defines macros for both C and assembler use. Their
++ * syntax is slightly different, but they're semantically similar.
++ *
++ * See the ELF specification for more detail about ELF notes.
++ */
++
++#ifdef __ASSEMBLER__
++/*
++ * Generate a structure with the same shape as Elf{32,64}_Nhdr (which
++ * turn out to be the same size and shape), followed by the name and
++ * desc data with appropriate padding. The 'desc' argument includes
++ * the assembler pseudo op defining the type of the data: .asciz
++ * "hello, world"
++ */
++.macro ELFNOTE name type desc:vararg
++.pushsection ".note.\name"
++ .align 4
++ .long 2f - 1f /* namesz */
++ .long 4f - 3f /* descsz */
++ .long \type
++1:.asciz "\name"
++2:.align 4
++3:\desc
++4:.align 4
++.popsection
++.endm
++#else /* !__ASSEMBLER__ */
++#include <linux/elf.h>
++/*
++ * Use an anonymous structure which matches the shape of
++ * Elf{32,64}_Nhdr, but includes the name and desc data. The size and
++ * type of name and desc depend on the macro arguments. "name" must
++ * be a literal string, and "desc" must be passed by value. You may
++ * only define one note per line, since __LINE__ is used to generate
++ * unique symbols.
++ */
++#define _ELFNOTE_PASTE(a,b) a##b
++#define _ELFNOTE(size, name, unique, type, desc) \
++ static const struct { \
++ struct elf##size##_note _nhdr; \
++ unsigned char _name[sizeof(name)] \
++ __attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ typeof(desc) _desc \
++
__attribute__((aligned(sizeof(Elf##size##_Word)))); \
++ } _ELFNOTE_PASTE(_note_, unique) \
++ __attribute_used__ \
++ __attribute__((section(".note." name), \
++ aligned(sizeof(Elf##size##_Word)), \
++ unused)) = { \
++ { \
++ sizeof(name), \
++ sizeof(desc), \
++ type, \
++ }, \
++ name, \
++ desc \
++ }
++#define ELFNOTE(size, name, type, desc) \
++ _ELFNOTE(size, name, __LINE__, type, desc)
++
++#define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc)
++#define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc)
++#endif /* __ASSEMBLER__ */
++
++#endif /* _LINUX_ELFNOTE_H */
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++
b/patches/linux-2.6.16.29/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,84 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/vmlinux.lds.S
./arch/x86_64/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/vmlinux.lds.S 2006-09-12
19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/vmlinux.lds.S 2006-09-19 14:06:15.000000000 +0100
+@@ -14,6 +14,12 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86
+ OUTPUT_ARCH(i386:x86-64)
+ ENTRY(phys_startup_64)
+ jiffies_64 = jiffies;
++PHDRS {
++ text PT_LOAD FLAGS(5); /* R_E */
++ data PT_LOAD FLAGS(7); /* RWE */
++ user PT_LOAD FLAGS(7); /* RWE */
++ note PT_NOTE FLAGS(4); /* R__ */
++}
+ SECTIONS
+ {
+ . = __START_KERNEL;
+@@ -26,7 +32,7 @@ SECTIONS
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+- } = 0x9090
++ } :text = 0x9090
+ /* out-of-line lock text */
+ .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
+
+@@ -43,17 +49,10 @@ SECTIONS
+ .data : AT(ADDR(.data) - LOAD_OFFSET) {
+ *(.data)
+ CONSTRUCTORS
+- }
++ } :data
+
+ _edata = .; /* End of data section */
+
+- __bss_start = .; /* BSS */
+- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+- *(.bss.page_aligned)
+- *(.bss)
+- }
+- __bss_stop = .;
+-
+ . = ALIGN(PAGE_SIZE);
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+@@ -75,7 +74,7 @@ SECTIONS
+ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+ . = VSYSCALL_ADDR;
+- .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) }
++ .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user
+ __vsyscall_0 = VSYSCALL_VIRT_ADDR;
+
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+@@ -118,7 +117,7 @@ SECTIONS
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+ *(.data.init_task)
+- }
++ } :data
+
+ . = ALIGN(4096);
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+@@ -188,6 +187,14 @@ SECTIONS
+ . = ALIGN(4096);
+ __nosave_end = .;
+
++ __bss_start = .; /* BSS */
++ . = ALIGN(4096);
++ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
++ *(.bss.page_aligned)
++ *(.bss)
++ }
++ __bss_stop = .;
++
+ _end = . ;
+
+ /* Sections to be discarded */
+@@ -201,4 +208,6 @@ SECTIONS
+ STABS_DEBUG
+
+ DWARF_DEBUG
++
++ NOTES
+ }
diff -r c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.29/xen-hotplug.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/xen-hotplug.patch Tue Sep 19 14:26:47 2006 +0100
@@ -0,0 +1,12 @@
+diff -pruN ../orig-linux-2.6.16.29/fs/proc/proc_misc.c ./fs/proc/proc_misc.c
+--- ../orig-linux-2.6.16.29/fs/proc/proc_misc.c 2006-09-12
19:02:10.000000000 +0100
++++ ./fs/proc/proc_misc.c 2006-09-19 14:06:00.000000000 +0100
+@@ -433,7 +433,7 @@ static int show_stat(struct seq_file *p,
+ (unsigned long long)cputime64_to_clock_t(irq),
+ (unsigned long long)cputime64_to_clock_t(softirq),
+ (unsigned long long)cputime64_to_clock_t(steal));
+- for_each_online_cpu(i) {
++ for_each_cpu(i) {
+
+ /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
+ user = kstat_cpu(i).cpustat.user;
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.29/xenoprof-generic.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.29/xenoprof-generic.patch Tue Sep 19 14:26:47
2006 +0100
@@ -0,0 +1,615 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/buffer_sync.c
./drivers/oprofile/buffer_sync.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/buffer_sync.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/buffer_sync.c 2006-09-19 14:06:05.000000000 +0100
+@@ -6,6 +6,10 @@
+ *
+ * @author John Levon <levon@xxxxxxxxxxxxxxxxx>
+ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+ * This is the core of the buffer management. Each
+ * CPU buffer is processed and entered into the
+ * global event buffer. Such processing is necessary
+@@ -275,15 +279,31 @@ static void add_cpu_switch(int i)
+ last_cookie = INVALID_COOKIE;
+ }
+
+-static void add_kernel_ctx_switch(unsigned int in_kernel)
++static void add_cpu_mode_switch(unsigned int cpu_mode)
+ {
+ add_event_entry(ESCAPE_CODE);
+- if (in_kernel)
+- add_event_entry(KERNEL_ENTER_SWITCH_CODE);
+- else
+- add_event_entry(KERNEL_EXIT_SWITCH_CODE);
++ switch (cpu_mode) {
++ case CPU_MODE_USER:
++ add_event_entry(USER_ENTER_SWITCH_CODE);
++ break;
++ case CPU_MODE_KERNEL:
++ add_event_entry(KERNEL_ENTER_SWITCH_CODE);
++ break;
++ case CPU_MODE_XEN:
++ add_event_entry(XEN_ENTER_SWITCH_CODE);
++ break;
++ default:
++ break;
++ }
+ }
+-
++
++static void add_domain_switch(unsigned long domain_id)
++{
++ add_event_entry(ESCAPE_CODE);
++ add_event_entry(DOMAIN_SWITCH_CODE);
++ add_event_entry(domain_id);
++}
++
+ static void
+ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+ {
+@@ -348,9 +368,9 @@ static int add_us_sample(struct mm_struc
+ * for later lookup from userspace.
+ */
+ static int
+-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
++add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode)
+ {
+- if (in_kernel) {
++ if (cpu_mode >= CPU_MODE_KERNEL) {
+ add_sample_entry(s->eip, s->event);
+ return 1;
+ } else if (mm) {
+@@ -496,10 +516,11 @@ void sync_buffer(int cpu)
+ struct mm_struct *mm = NULL;
+ struct task_struct * new;
+ unsigned long cookie = 0;
+- int in_kernel = 1;
++ int cpu_mode = 1;
+ unsigned int i;
+ sync_buffer_state state = sb_buffer_start;
+ unsigned long available;
++ int domain_switch = 0;
+
+ down(&buffer_sem);
+
+@@ -512,16 +533,18 @@ void sync_buffer(int cpu)
+ for (i = 0; i < available; ++i) {
+ struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
+- if (is_code(s->eip)) {
+- if (s->event <= CPU_IS_KERNEL) {
+- /* kernel/userspace switch */
+- in_kernel = s->event;
++ if (is_code(s->eip) && !domain_switch) {
++ if (s->event <= CPU_MODE_XEN) {
++ /* xen/kernel/userspace switch */
++ cpu_mode = s->event;
+ if (state == sb_buffer_start)
+ state = sb_sample_start;
+- add_kernel_ctx_switch(s->event);
++ add_cpu_mode_switch(s->event);
+ } else if (s->event == CPU_TRACE_BEGIN) {
+ state = sb_bt_start;
+ add_trace_begin();
++ } else if (s->event == CPU_DOMAIN_SWITCH) {
++ domain_switch = 1;
+ } else {
+ struct mm_struct * oldmm = mm;
+
+@@ -535,11 +558,16 @@ void sync_buffer(int cpu)
+ add_user_ctx_switch(new, cookie);
+ }
+ } else {
+- if (state >= sb_bt_start &&
+- !add_sample(mm, s, in_kernel)) {
+- if (state == sb_bt_start) {
+- state = sb_bt_ignore;
+-
atomic_inc(&oprofile_stats.bt_lost_no_mapping);
++ if (domain_switch) {
++ add_domain_switch(s->eip);
++ domain_switch = 0;
++ } else {
++ if (state >= sb_bt_start &&
++ !add_sample(mm, s, cpu_mode)) {
++ if (state == sb_bt_start) {
++ state = sb_bt_ignore;
++
atomic_inc(&oprofile_stats.bt_lost_no_mapping);
++ }
+ }
+ }
+ }
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.c
./drivers/oprofile/cpu_buffer.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/cpu_buffer.c 2006-09-19 14:06:05.000000000 +0100
+@@ -6,6 +6,10 @@
+ *
+ * @author John Levon <levon@xxxxxxxxxxxxxxxxx>
+ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+ * Each CPU has a local buffer that stores PC value/event
+ * pairs. We also log context switches when we notice them.
+ * Eventually each CPU's buffer is processed into the global
+@@ -34,6 +38,8 @@ static void wq_sync_buffer(void *);
+ #define DEFAULT_TIMER_EXPIRE (HZ / 10)
+ static int work_enabled;
+
++static int32_t current_domain = COORDINATOR_DOMAIN;
++
+ void free_cpu_buffers(void)
+ {
+ int i;
+@@ -58,7 +64,7 @@ int alloc_cpu_buffers(void)
+ goto fail;
+
+ b->last_task = NULL;
+- b->last_is_kernel = -1;
++ b->last_cpu_mode = -1;
+ b->tracing = 0;
+ b->buffer_size = buffer_size;
+ b->tail_pos = 0;
+@@ -114,7 +120,7 @@ void cpu_buffer_reset(struct oprofile_cp
+ * collected will populate the buffer with proper
+ * values to initialize the buffer
+ */
+- cpu_buf->last_is_kernel = -1;
++ cpu_buf->last_cpu_mode = -1;
+ cpu_buf->last_task = NULL;
+ }
+
+@@ -164,13 +170,13 @@ add_code(struct oprofile_cpu_buffer * bu
+ * because of the head/tail separation of the writer and reader
+ * of the CPU buffer.
+ *
+- * is_kernel is needed because on some architectures you cannot
++ * cpu_mode is needed because on some architectures you cannot
+ * tell if you are in kernel or user space simply by looking at
+- * pc. We tag this in the buffer by generating kernel enter/exit
+- * events whenever is_kernel changes
++ * pc. We tag this in the buffer by generating kernel/user (and xen)
++ * enter events whenever cpu_mode changes
+ */
+ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
+- int is_kernel, unsigned long event)
++ int cpu_mode, unsigned long event)
+ {
+ struct task_struct * task;
+
+@@ -181,18 +187,18 @@ static int log_sample(struct oprofile_cp
+ return 0;
+ }
+
+- is_kernel = !!is_kernel;
+-
+ task = current;
+
+ /* notice a switch from user->kernel or vice versa */
+- if (cpu_buf->last_is_kernel != is_kernel) {
+- cpu_buf->last_is_kernel = is_kernel;
+- add_code(cpu_buf, is_kernel);
++ if (cpu_buf->last_cpu_mode != cpu_mode) {
++ cpu_buf->last_cpu_mode = cpu_mode;
++ add_code(cpu_buf, cpu_mode);
+ }
+-
++
+ /* notice a task switch */
+- if (cpu_buf->last_task != task) {
++ /* if not processing other domain samples */
++ if ((cpu_buf->last_task != task) &&
++ (current_domain == COORDINATOR_DOMAIN)) {
+ cpu_buf->last_task = task;
+ add_code(cpu_buf, (unsigned long)task);
+ }
+@@ -269,6 +275,25 @@ void oprofile_add_trace(unsigned long pc
+ add_sample(cpu_buf, pc, 0);
+ }
+
++int oprofile_add_domain_switch(int32_t domain_id)
++{
++ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
++
++ /* should have space for switching into and out of domain
++ (2 slots each) plus one sample and one cpu mode switch */
++ if (((nr_available_slots(cpu_buf) < 6) &&
++ (domain_id != COORDINATOR_DOMAIN)) ||
++ (nr_available_slots(cpu_buf) < 2))
++ return 0;
++
++ add_code(cpu_buf, CPU_DOMAIN_SWITCH);
++ add_sample(cpu_buf, domain_id, 0);
++
++ current_domain = domain_id;
++
++ return 1;
++}
++
+ /*
+ * This serves to avoid cpu buffer overflow, and makes sure
+ * the task mortuary progresses
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.h
./drivers/oprofile/cpu_buffer.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.h 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/cpu_buffer.h 2006-09-19 14:06:05.000000000 +0100
+@@ -36,7 +36,7 @@ struct oprofile_cpu_buffer {
+ volatile unsigned long tail_pos;
+ unsigned long buffer_size;
+ struct task_struct * last_task;
+- int last_is_kernel;
++ int last_cpu_mode;
+ int tracing;
+ struct op_sample * buffer;
+ unsigned long sample_received;
+@@ -51,7 +51,10 @@ extern struct oprofile_cpu_buffer cpu_bu
+ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
+
+ /* transient events for the CPU buffer -> event buffer */
+-#define CPU_IS_KERNEL 1
+-#define CPU_TRACE_BEGIN 2
++#define CPU_MODE_USER 0
++#define CPU_MODE_KERNEL 1
++#define CPU_MODE_XEN 2
++#define CPU_TRACE_BEGIN 3
++#define CPU_DOMAIN_SWITCH 4
+
+ #endif /* OPROFILE_CPU_BUFFER_H */
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/event_buffer.h
./drivers/oprofile/event_buffer.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/event_buffer.h 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/event_buffer.h 2006-09-19 14:06:05.000000000 +0100
+@@ -29,15 +29,20 @@ void wake_up_buffer_waiter(void);
+ #define CPU_SWITCH_CODE 2
+ #define COOKIE_SWITCH_CODE 3
+ #define KERNEL_ENTER_SWITCH_CODE 4
+-#define KERNEL_EXIT_SWITCH_CODE 5
++#define USER_ENTER_SWITCH_CODE 5
+ #define MODULE_LOADED_CODE 6
+ #define CTX_TGID_CODE 7
+ #define TRACE_BEGIN_CODE 8
+ #define TRACE_END_CODE 9
++#define XEN_ENTER_SWITCH_CODE 10
++#define DOMAIN_SWITCH_CODE 11
+
+ #define INVALID_COOKIE ~0UL
+ #define NO_COOKIE 0UL
+
++/* Constant used to refer to coordinator domain (Xen) */
++#define COORDINATOR_DOMAIN -1
++
+ /* add data to the event buffer */
+ void add_event_entry(unsigned long data);
+
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprof.c
./drivers/oprofile/oprof.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprof.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/oprof.c 2006-09-19 14:06:05.000000000 +0100
+@@ -5,6 +5,10 @@
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@xxxxxxxxxxxxxxxxx>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
+ */
+
+ #include <linux/kernel.h>
+@@ -19,7 +23,7 @@
+ #include "cpu_buffer.h"
+ #include "buffer_sync.h"
+ #include "oprofile_stats.h"
+-
++
+ struct oprofile_operations oprofile_ops;
+
+ unsigned long oprofile_started;
+@@ -33,6 +37,32 @@ static DECLARE_MUTEX(start_sem);
+ */
+ static int timer = 0;
+
++int oprofile_set_active(int active_domains[], unsigned int adomains)
++{
++ int err;
++
++ if (!oprofile_ops.set_active)
++ return -EINVAL;
++
++ down(&start_sem);
++ err = oprofile_ops.set_active(active_domains, adomains);
++ up(&start_sem);
++ return err;
++}
++
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
++{
++ int err;
++
++ if (!oprofile_ops.set_passive)
++ return -EINVAL;
++
++ down(&start_sem);
++ err = oprofile_ops.set_passive(passive_domains, pdomains);
++ up(&start_sem);
++ return err;
++}
++
+ int oprofile_setup(void)
+ {
+ int err;
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprof.h
./drivers/oprofile/oprof.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprof.h 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/oprof.h 2006-09-19 14:06:05.000000000 +0100
+@@ -35,5 +35,8 @@ void oprofile_create_files(struct super_
+ void oprofile_timer_init(struct oprofile_operations * ops);
+
+ int oprofile_set_backtrace(unsigned long depth);
++
++int oprofile_set_active(int active_domains[], unsigned int adomains);
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains);
+
+ #endif /* OPROF_H */
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprofile_files.c
./drivers/oprofile/oprofile_files.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprofile_files.c 2006-09-12
19:02:10.000000000 +0100
++++ ./drivers/oprofile/oprofile_files.c 2006-09-19 14:06:05.000000000
+0100
+@@ -5,15 +5,21 @@
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@xxxxxxxxxxxxxxxxx>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
+ */
+
+ #include <linux/fs.h>
+ #include <linux/oprofile.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
+
+ #include "event_buffer.h"
+ #include "oprofile_stats.h"
+ #include "oprof.h"
+-
++
+ unsigned long fs_buffer_size = 131072;
+ unsigned long fs_cpu_buffer_size = 8192;
+ unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
+@@ -117,11 +123,202 @@ static ssize_t dump_write(struct file *
+ static struct file_operations dump_fops = {
+ .write = dump_write,
+ };
+-
++
++#define TMPBUFSIZE 512
++
++static unsigned int adomains = 0;
++static int active_domains[MAX_OPROF_DOMAINS + 1];
++static DEFINE_MUTEX(adom_mutex);
++
++static ssize_t adomain_write(struct file * file, char const __user * buf,
++ size_t count, loff_t * offset)
++{
++ char *tmpbuf;
++ char *startp, *endp;
++ int i;
++ unsigned long val;
++ ssize_t retval = count;
++
++ if (*offset)
++ return -EINVAL;
++ if (count > TMPBUFSIZE - 1)
++ return -EINVAL;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ if (copy_from_user(tmpbuf, buf, count)) {
++ kfree(tmpbuf);
++ return -EFAULT;
++ }
++ tmpbuf[count] = 0;
++
++ mutex_lock(&adom_mutex);
++
++ startp = tmpbuf;
++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++ val = simple_strtoul(startp, &endp, 0);
++ if (endp == startp)
++ break;
++ while (ispunct(*endp) || isspace(*endp))
++ endp++;
++ active_domains[i] = val;
++ if (active_domains[i] != val)
++ /* Overflow, force error below */
++ i = MAX_OPROF_DOMAINS + 1;
++ startp = endp;
++ }
++ /* Force error on trailing junk */
++ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++ kfree(tmpbuf);
++
++ if (adomains > MAX_OPROF_DOMAINS
++ || oprofile_set_active(active_domains, adomains)) {
++ adomains = 0;
++ retval = -EINVAL;
++ }
++
++ mutex_unlock(&adom_mutex);
++ return retval;
++}
++
++static ssize_t adomain_read(struct file * file, char __user * buf,
++ size_t count, loff_t * offset)
++{
++ char * tmpbuf;
++ size_t len;
++ int i;
++ ssize_t retval;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ mutex_lock(&adom_mutex);
++
++ len = 0;
++ for (i = 0; i < adomains; i++)
++ len += snprintf(tmpbuf + len,
++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++ "%u ", active_domains[i]);
++ WARN_ON(len > TMPBUFSIZE);
++ if (len != 0 && len <= TMPBUFSIZE)
++ tmpbuf[len-1] = '\n';
++
++ mutex_unlock(&adom_mutex);
++
++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++ kfree(tmpbuf);
++ return retval;
++}
++
++
++static struct file_operations active_domain_ops = {
++ .read = adomain_read,
++ .write = adomain_write,
++};
++
++static unsigned int pdomains = 0;
++static int passive_domains[MAX_OPROF_DOMAINS];
++static DEFINE_MUTEX(pdom_mutex);
++
++static ssize_t pdomain_write(struct file * file, char const __user * buf,
++ size_t count, loff_t * offset)
++{
++ char *tmpbuf;
++ char *startp, *endp;
++ int i;
++ unsigned long val;
++ ssize_t retval = count;
++
++ if (*offset)
++ return -EINVAL;
++ if (count > TMPBUFSIZE - 1)
++ return -EINVAL;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ if (copy_from_user(tmpbuf, buf, count)) {
++ kfree(tmpbuf);
++ return -EFAULT;
++ }
++ tmpbuf[count] = 0;
++
++ mutex_lock(&pdom_mutex);
++
++ startp = tmpbuf;
++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++ val = simple_strtoul(startp, &endp, 0);
++ if (endp == startp)
++ break;
++ while (ispunct(*endp) || isspace(*endp))
++ endp++;
++ passive_domains[i] = val;
++ if (passive_domains[i] != val)
++ /* Overflow, force error below */
++ i = MAX_OPROF_DOMAINS + 1;
++ startp = endp;
++ }
++ /* Force error on trailing junk */
++ pdomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++ kfree(tmpbuf);
++
++ if (pdomains > MAX_OPROF_DOMAINS
++ || oprofile_set_passive(passive_domains, pdomains)) {
++ pdomains = 0;
++ retval = -EINVAL;
++ }
++
++ mutex_unlock(&pdom_mutex);
++ return retval;
++}
++
++static ssize_t pdomain_read(struct file * file, char __user * buf,
++ size_t count, loff_t * offset)
++{
++ char * tmpbuf;
++ size_t len;
++ int i;
++ ssize_t retval;
++
++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++ return -ENOMEM;
++
++ mutex_lock(&pdom_mutex);
++
++ len = 0;
++ for (i = 0; i < pdomains; i++)
++ len += snprintf(tmpbuf + len,
++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++ "%u ", passive_domains[i]);
++ WARN_ON(len > TMPBUFSIZE);
++ if (len != 0 && len <= TMPBUFSIZE)
++ tmpbuf[len-1] = '\n';
++
++ mutex_unlock(&pdom_mutex);
++
++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++ kfree(tmpbuf);
++ return retval;
++}
++
++static struct file_operations passive_domain_ops = {
++ .read = pdomain_read,
++ .write = pdomain_write,
++};
++
+ void oprofile_create_files(struct super_block * sb, struct dentry * root)
+ {
+ oprofilefs_create_file(sb, root, "enable", &enable_fops);
+ oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
++ oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
++ oprofilefs_create_file(sb, root, "passive_domains",
&passive_domain_ops);
+ oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
+ oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
+ oprofilefs_create_ulong(sb, root, "buffer_watershed",
&fs_buffer_watershed);
+diff -pruN ../orig-linux-2.6.16.29/include/linux/oprofile.h
./include/linux/oprofile.h
+--- ../orig-linux-2.6.16.29/include/linux/oprofile.h 2006-09-12
19:02:10.000000000 +0100
++++ ./include/linux/oprofile.h 2006-09-19 14:06:05.000000000 +0100
+@@ -16,6 +16,8 @@
+ #include <linux/types.h>
+ #include <linux/spinlock.h>
+ #include <asm/atomic.h>
++
++#include <xen/interface/xenoprof.h>
+
+ struct super_block;
+ struct dentry;
+@@ -27,6 +29,11 @@ struct oprofile_operations {
+ /* create any necessary configuration files in the oprofile fs.
+ * Optional. */
+ int (*create_files)(struct super_block * sb, struct dentry * root);
++ /* setup active domains with Xen */
++ int (*set_active)(int *active_domains, unsigned int adomains);
++ /* setup passive domains with Xen */
++ int (*set_passive)(int *passive_domains, unsigned int pdomains);
++
+ /* Do any necessary interrupt setup. Optional. */
+ int (*setup)(void);
+ /* Do any necessary interrupt shutdown. Optional. */
+@@ -68,6 +75,8 @@ void oprofile_add_pc(unsigned long pc, i
+ /* add a backtrace entry, to be called from the ->backtrace callback */
+ void oprofile_add_trace(unsigned long eip);
+
++/* add a domain switch entry */
++int oprofile_add_domain_switch(int32_t domain_id);
+
+ /**
+ * Create a file of the given name as a child of the given root, with
diff -r c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/blktap-aio-16_03_06.patch
--- a/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch Tue Sep 19 14:26:22
2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
---- ../pristine-linux-2.6.16-rc5/fs/aio.c 2006-03-14 14:10:10.827401387
+0000
-+++ ./fs/aio.c 2006-03-16 09:57:53.898316582 +0000
-@@ -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 ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
---- ../pristine-linux-2.6.16-rc5/fs/eventpoll.c 2006-01-03
03:21:10.000000000 +0000
-+++ ./fs/eventpoll.c 2006-03-16 10:04:35.469956167 +0000
-@@ -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 ../pristine-linux-2.6.16-rc5/include/linux/aio.h
./include/linux/aio.h
---- ../pristine-linux-2.6.16-rc5/include/linux/aio.h 2006-03-14
14:10:21.597916731 +0000
-+++ ./include/linux/aio.h 2006-03-16 10:05:39.848833028 +0000
-@@ -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 ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h
./include/linux/eventpoll.h
---- ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h 2006-01-03
03:21:10.000000000 +0000
-+++ ./include/linux/eventpoll.h 2006-03-16 10:08:51.577809317 +0000
-@@ -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 c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.13/device_bind.patch
--- a/patches/linux-2.6.16.13/device_bind.patch Tue Sep 19 14:26:22 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-diff -pruN ../pristine-linux-2.6.16.13/drivers/base/bus.c ./drivers/base/bus.c
---- ../pristine-linux-2.6.16.13/drivers/base/bus.c 2006-05-02
22:38:44.000000000 +0100
-+++ ./drivers/base/bus.c 2006-05-04 17:41:30.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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/fix-hz-suspend.patch
--- a/patches/linux-2.6.16.13/fix-hz-suspend.patch Tue Sep 19 14:26:22
2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-diff -pruN ../pristine-linux-2.6.16.13/kernel/timer.c ./kernel/timer.c
---- ../pristine-linux-2.6.16.13/kernel/timer.c 2006-05-02 22:38:44.000000000
+0100
-+++ ./kernel/timer.c 2006-06-29 14:34:12.788957720 +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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch
--- a/patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch Tue Sep 19 14:26:22
2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-diff -ru ../pristine-linux-2.6.16.13/drivers/ide/ide-lib.c
./drivers/ide/ide-lib.c
---- ../pristine-linux-2.6.16.13/drivers/ide/ide-lib.c 2006-05-02
22:38:44.000000000 +0100
-+++ ./drivers/ide/ide-lib.c 2006-05-24 18:37:05.000000000 +0100
-@@ -410,10 +410,10 @@
- {
- 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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch
--- a/patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch Tue Sep 19
14:26:22 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/traps.c
./arch/i386/kernel/traps.c
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/traps.c 2006-05-02
22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/traps.c 2006-05-04 17:41:34.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
../pristine-linux-2.6.16.13/include/asm-i386/mach-default/mach_traps.h
./include/asm-i386/mach-default/mach_traps.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/mach-default/mach_traps.h
2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/mach-default/mach_traps.h 2006-05-04
17:41:34.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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/ipv6-no-autoconf.patch
--- a/patches/linux-2.6.16.13/ipv6-no-autoconf.patch Tue Sep 19 14:26:22
2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
- net/ipv6/addrconf.c | 2 ++
- 1 files changed, 2 insertions(+)
-
-Index: build/net/ipv6/addrconf.c
-===================================================================
---- build.orig/net/ipv6/addrconf.c
-+++ build/net/ipv6/addrconf.c
-@@ -2462,6 +2462,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);
-@@ -2546,6 +2547,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 c5d4d47bbeb8 -r 041be3f6b38e patches/linux-2.6.16.13/net-csum.patch
--- a/patches/linux-2.6.16.13/net-csum.patch Tue Sep 19 14:26:22 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c
./net/ipv4/netfilter/ip_nat_proto_tcp.c
---- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c
2006-05-02 22:38:44.000000000 +0100
-+++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-05-16 13:28:19.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 ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c
./net/ipv4/netfilter/ip_nat_proto_udp.c
---- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c
2006-05-02 22:38:44.000000000 +0100
-+++ ./net/ipv4/netfilter/ip_nat_proto_udp.c 2006-05-16 13:30:14.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 ../pristine-linux-2.6.16.13/net/ipv4/xfrm4_output.c
./net/ipv4/xfrm4_output.c
---- ../pristine-linux-2.6.16.13/net/ipv4/xfrm4_output.c 2006-05-02
22:38:44.000000000 +0100
-+++ ./net/ipv4/xfrm4_output.c 2006-05-04 17:41:37.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 c5d4d47bbeb8 -r 041be3f6b38e
patches/linux-2.6.16.13/net-gso-0-base.patch
--- a/patches/linux-2.6.16.13/net-gso-0-base.patch Tue Sep 19 14:26:22
2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2907 +0,0 @@
-diff --git a/Documentation/networking/netdevices.txt
b/Documentation/networking/netdevices.txt
-index 3c0a5ba..847cedb 100644
---- a/Documentation/networking/netdevices.txt
-+++ b/Documentation/networking/netdevices.txt
-@@ -42,9 +42,9 @@ dev->get_stats:
- 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 @@ dev->hard_start_xmit:
- 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:
-diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
-index 4be9769..2e7cac7 100644
---- a/drivers/block/aoe/aoenet.c
-+++ b/drivers/block/aoe/aoenet.c
-@@ -95,9 +95,8 @@ mac_addr(char addr[6])
- 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;
- }
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-index a2408d7..c90e620 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-@@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_
-
- 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 @@ void ipoib_mcast_restart_task(void *dev_
- }
-
- 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) {
-diff --git a/drivers/media/dvb/dvb-core/dvb_net.c
b/drivers/media/dvb/dvb-core/dvb_net.c
-index 6711eb6..8d2351f 100644
---- a/drivers/media/dvb/dvb-core/dvb_net.c
-+++ b/drivers/media/dvb/dvb-core/dvb_net.c
-@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void
-
- 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);
-@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void
- }
- }
-
-- spin_unlock_bh(&dev->xmit_lock);
-+ netif_tx_unlock_bh(dev);
- dvb_net_feed_start(dev);
- }
-
-diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
-index dd41049..6615583 100644
---- a/drivers/net/8139cp.c
-+++ b/drivers/net/8139cp.c
-@@ -794,7 +794,7 @@ #endif
- 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];
-diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
-index a24200d..b5e39a1 100644
---- a/drivers/net/bnx2.c
-+++ b/drivers/net/bnx2.c
-@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
- 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 @@ bnx2_poll(struct net_device *dev, int *b
- 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 @@ bnx2_vlan_rx_kill_vid(struct net_device
- }
- #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 @@ bnx2_start_xmit(struct sk_buff *skb, str
- (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;
-
-diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
-index bcf9f17..e970921 100644
---- a/drivers/net/bonding/bond_main.c
-+++ b/drivers/net/bonding/bond_main.c
-@@ -1145,8 +1145,7 @@ int bond_sethwaddr(struct net_device *bo
- }
-
- #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 @@ static int bond_compute_features(struct
- 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 @@ static int bond_init(struct net_device *
- */
- 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;
-
-diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
-index 30ff8ea..7b7d360 100644
---- a/drivers/net/chelsio/sge.c
-+++ b/drivers/net/chelsio/sge.c
-@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
- 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 @@ #ifdef NETIF_F_TSO
- 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++;
-diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
-index fa29402..681d284 100644
---- a/drivers/net/e1000/e1000_main.c
-+++ b/drivers/net/e1000/e1000_main.c
-@@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO
- 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 @@ #ifdef NETIF_F_TSO
- }
-
- 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 @@ #ifdef NETIF_F_TSO
- * 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 @@ #endif
- }
-
- #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 @@ #endif
- #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
-
-diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
-index 3682ec6..c35f16e 100644
---- a/drivers/net/forcedeth.c
-+++ b/drivers/net/forcedeth.c
-@@ -482,9 +482,9 @@ #define LPA_1000HALF 0x0400
- * 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 @@ static void drain_ring(struct net_device
-
- /*
- * 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 @@ static int nv_start_xmit(struct sk_buff
- 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 @@ static void nv_tx_done(struct net_device
-
- /*
- * 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 @@ static int nv_change_mtu(struct net_devi
- * 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 @@ static int nv_change_mtu(struct net_devi
- 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 @@ static int nv_set_mac_address(struct net
- 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 @@ static int nv_set_mac_address(struct net
- /* 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 @@ static int nv_set_mac_address(struct net
-
- /*
- * 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)
- {
-diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
-index 102c1f0..d12605f 100644
---- a/drivers/net/hamradio/6pack.c
-+++ b/drivers/net/hamradio/6pack.c
-@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net
- {
- 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 @@ static int sixpack_ioctl(struct tty_stru
- 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;
-diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
-index dc5e9d5..5c66f5a 100644
---- a/drivers/net/hamradio/mkiss.c
-+++ b/drivers/net/hamradio/mkiss.c
-@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net
- {
- 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 @@ static int mkiss_ioctl(struct tty_struct
- 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;
-diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
-index 31fb2d7..2e222ef 100644
---- a/drivers/net/ifb.c
-+++ b/drivers/net/ifb.c
-@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev
- 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 @@ static void ri_tasklet(unsigned long dev
- }
- }
-
-- 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 @@ static void ri_tasklet(unsigned long dev
- 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;
-diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
-index a9f49f0..339d4a7 100644
---- a/drivers/net/irda/vlsi_ir.c
-+++ b/drivers/net/irda/vlsi_ir.c
-@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct s
- || (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! */
- }
- }
-
-diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
-index f9f77e4..bdab369 100644
---- a/drivers/net/ixgb/ixgb_main.c
-+++ b/drivers/net/ixgb/ixgb_main.c
-@@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO
- 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 @@ #ifdef NETIF_F_TSO
- }
-
- 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,
-diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
-index 690a1aa..9bcaa80 100644
---- a/drivers/net/loopback.c
-+++ b/drivers/net/loopback.c
-@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
- 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 @@ #ifndef LOOPBACK_MUST_CHECKSUM
- #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);
-
-diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
-index c0998ef..0fac9d5 100644
---- a/drivers/net/mv643xx_eth.c
-+++ b/drivers/net/mv643xx_eth.c
-@@ -1107,7 +1107,7 @@ static int mv643xx_eth_start_xmit(struct
-
- #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);
-diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
-index 9d6d254..c9ed624 100644
---- a/drivers/net/natsemi.c
-+++ b/drivers/net/natsemi.c
-@@ -323,12 +323,12 @@ performance critical codepaths:
- 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
-diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
-index 8cc0d0b..e53b313 100644
---- a/drivers/net/r8169.c
-+++ b/drivers/net/r8169.c
-@@ -2171,7 +2171,7 @@ static int rtl8169_xmit_frags(struct rtl
- 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);
-diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
-index b7f00d6..439f45f 100644
---- a/drivers/net/s2io.c
-+++ b/drivers/net/s2io.c
-@@ -3522,8 +3522,8 @@ #endif
- 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 @@ #endif
- }
-
- 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 @@ #endif
- 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 @@ #endif
- (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 @@ #ifdef NETIF_F_TSO
- 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);
-
-diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
-index 0618cd5..2a55eb3 100644
---- a/drivers/net/sky2.c
-+++ b/drivers/net/sky2.c
-@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
- 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)
-@@ -1197,7 +1197,7 @@ static int sky2_xmit_frame(struct sk_buf
- }
-
- /* 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) &&
-diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
-index caf4102..fc9164a 100644
---- a/drivers/net/tg3.c
-+++ b/drivers/net/tg3.c
-@@ -3664,7 +3664,7 @@ static int tg3_start_xmit(struct sk_buff
- #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) &&
-diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
-index 5b1af39..11de5af 100644
---- a/drivers/net/tulip/winbond-840.c
-+++ b/drivers/net/tulip/winbond-840.c
-@@ -1605,11 +1605,11 @@ #ifdef CONFIG_PM
- * - 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 @@ static int w840_suspend (struct pci_dev
- 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;
-
-diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
-index 4c76cb7..30c48c9 100644
---- a/drivers/net/typhoon.c
-+++ b/drivers/net/typhoon.c
-@@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch
- #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
-diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
-index ed1f837..2eb6b5f 100644
---- a/drivers/net/via-velocity.c
-+++ b/drivers/net/via-velocity.c
-@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff
-
- 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];
-@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff
- */
- 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);
-@@ -1933,7 +1938,6 @@ #ifdef VELOCITY_ZERO_COPY_SUPPORT
- 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 =
-diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
-index 6fd0bf7..75237c1 100644
---- a/drivers/net/wireless/orinoco.c
-+++ b/drivers/net/wireless/orinoco.c
-@@ -1835,7 +1835,9 @@ static int __orinoco_program_rids(struct
- /* 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;
- }
-diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
-index 82cb4af..57cec40 100644
---- a/drivers/s390/net/qeth_eddp.c
-+++ b/drivers/s390/net/qeth_eddp.c
-@@ -421,7 +421,7 @@ #endif /* CONFIG_QETH_VLAN */
- }
- 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_eddp_calc_num_pages(struct qeth_edd
-
- 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 *
-diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
-index dba7f7f..d9cc997 100644
---- a/drivers/s390/net/qeth_main.c
-+++ b/drivers/s390/net/qeth_main.c
-@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
- 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 @@ qeth_send_packet(struct qeth_card *card,
- 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++;
-diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
-index 1286dde..89cbf34 100644
---- a/drivers/s390/net/qeth_tso.h
-+++ b/drivers/s390/net/qeth_tso.h
-@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
- 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));
-diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
-index 93535f0..9269df7 100644
---- a/include/linux/ethtool.h
-+++ b/include/linux/ethtool.h
-@@ -408,6 +408,8 @@ #define ETHTOOL_STSO 0x0000001f /* Set
- #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
-diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 7fda03d..47b0965 100644
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -230,7 +230,8 @@ enum netdev_state_t
- __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_TX 128 /* Transm
- #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 @@ #define NETIF_F_UFO 8192
- 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 @@ #define NETIF_F_UFO 8192
- * 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 packet_type {
- 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_change_name(struct net_d
- 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 @@ static inline void __netif_rx_complete(s
- 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 netdev_max_backlog;
- 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 @@ #endif
-
- 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 */
-diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
-index ad7cc22..b19d45d 100644
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -134,9 +134,10 @@ struct skb_frag_struct {
- 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 @@ enum {
- 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 @@ static inline int skb_can_coalesce(struc
- 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 @@ extern void skb_split(struct sk_b
- 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)
-diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
-index b94d1ad..75b5b93 100644
---- a/include/net/pkt_sched.h
-+++ b/include/net/pkt_sched.h
-@@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_ge
- 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,
-diff --git a/include/net/protocol.h b/include/net/protocol.h
-index 6dc5970..0d2dcdb 100644
---- a/include/net/protocol.h
-+++ b/include/net/protocol.h
-@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS 256 /* Must be
- 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;
- };
-
-diff --git a/include/net/sock.h b/include/net/sock.h
-index f63d0d5..a8e8d21 100644
---- a/include/net/sock.h
-+++ b/include/net/sock.h
-@@ -1064,9 +1064,13 @@ static inline void sk_setup_caps(struct
- {
- __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;
- }
- }
-
-diff --git a/include/net/tcp.h b/include/net/tcp.h
-index 77f21c6..70e1d5f 100644
---- a/include/net/tcp.h
-+++ b/include/net/tcp.h
-@@ -552,13 +552,13 @@ #include <net/tcp_ecn.h>
- */
- 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 struct request_sock_ops tcp_reque
-
- 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);
-diff --git a/net/atm/clip.c b/net/atm/clip.c
-index 1842a4e..6dc21a7 100644
---- a/net/atm/clip.c
-+++ b/net/atm/clip.c
-@@ -101,7 +101,7 @@ static void unlink_clip_vcc(struct clip_
- 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 @@ static void unlink_clip_vcc(struct clip_
- 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. */
-diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
-index 0b33a7b..180e79b 100644
---- a/net/bridge/br_device.c
-+++ b/net/bridge/br_device.c
-@@ -146,9 +146,9 @@ static int br_set_tx_csum(struct net_dev
- 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 @@ void br_dev_setup(struct net_device *dev
- 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;
- }
-diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
-index 2d24fb4..00b1128 100644
---- a/net/bridge/br_forward.c
-+++ b/net/bridge/br_forward.c
-@@ -32,7 +32,7 @@ static inline int should_deliver(const s
- 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
-diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
-index f36b35e..0617146 100644
---- a/net/bridge/br_if.c
-+++ b/net/bridge/br_if.c
-@@ -385,17 +385,28 @@ void br_features_recompute(struct net_br
- 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 */
-diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
-index 9e27373..588207f 100644
---- a/net/bridge/br_netfilter.c
-+++ b/net/bridge/br_netfilter.c
-@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
- {
- 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);
-diff --git a/net/core/dev.c b/net/core/dev.c
-index 12a214c..32e1056 100644
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -115,6 +115,7 @@ #include <linux/wireless.h> /* Note : w
- #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 @@ static inline void net_timestamp(struct
- * 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 @@ out:
- 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,75 +1182,108 @@ #else
- #define illegal_highdma(dev, skb) (0)
- #endif
-
--/* Keep head the same: replace data */
--int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
--{
-- 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->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;
--
-- /* We are no longer a clone, even if we were. */
-- skb->cloned = 0;
--
-- skb->tail += skb->data_len;
-- skb->data_len = 0;
-+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)
-+{
-+ struct dev_gso_cb *cb;
-+
-+ do {
-+ struct sk_buff *nskb = skb->next;
-+
-+ 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); \
- } \
- }
-
-@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
- 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,
-@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
- */
- 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
-@@ -1309,8 +1387,8 @@ #endif
- /* 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.
-@@ -1326,11 +1404,8 @@ #endif
- 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;
- }
-@@ -1349,13 +1424,13 @@ #endif
- }
-
- 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;
- }
-
-@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
- 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);
-@@ -2714,9 +2789,7 @@ #endif
-
- /* 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;
-@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
- 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);
-diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
-index 05d6085..c57d887 100644
---- a/net/core/dev_mcast.c
-+++ b/net/core/dev_mcast.c
-@@ -62,7 +62,7 @@ #include <net/arp.h>
- * 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 @@ static void __dev_mc_upload(struct net_d
-
- 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 dev_mc_delete(struct net_device *dev
- 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 @@ int dev_mc_delete(struct net_device *dev
- */
- __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 @@ int dev_mc_add(struct net_device *dev, v
-
- 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 @@ int dev_mc_add(struct net_device *dev, v
- }
-
- 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 @@ int dev_mc_add(struct net_device *dev, v
-
- __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 @@ done:
-
- 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 @@ void dev_mc_discard(struct net_device *d
- }
- dev->mc_count = 0;
-
-- spin_unlock_bh(&dev->xmit_lock);
-+ netif_tx_unlock_bh(dev);
- }
-
- #ifdef CONFIG_PROC_FS
-@@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_fi
- 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 @@ static int dev_mc_seq_show(struct seq_fi
-
- seq_putc(seq, '\n');
- }
-- spin_unlock_bh(&dev->xmit_lock);
-+ netif_tx_unlock_bh(dev);
- return 0;
- }
-
-diff --git a/net/core/ethtool.c b/net/core/ethtool.c
-index e6f7610..27ce168 100644
---- a/net/core/ethtool.c
-+++ b/net/core/ethtool.c
-@@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_devic
-
- 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 @@ static int ethtool_set_sg(struct net_dev
- 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);
-@@ -591,7 +589,7 @@ static int ethtool_set_tso(struct net_de
-
- static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
- {
-- struct ethtool_value edata = { ETHTOOL_GTSO };
-+ struct ethtool_value edata = { ETHTOOL_GUFO };
-
- if (!dev->ethtool_ops->get_ufo)
- return -EOPNOTSUPP;
-@@ -600,6 +598,7 @@ static int ethtool_get_ufo(struct net_de
- return -EFAULT;
- return 0;
- }
-+
- static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
- {
- struct ethtool_value edata;
-@@ -615,6 +614,29 @@ static int ethtool_set_ufo(struct net_de
- 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;
-@@ -906,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
- 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;
- }
-diff --git a/net/core/netpoll.c b/net/core/netpoll.c
-index ea51f8d..ec28d3b 100644
---- a/net/core/netpoll.c
-+++ b/net/core/netpoll.c
-@@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netp
-
- 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) {
-diff --git a/net/core/pktgen.c b/net/core/pktgen.c
-index da16f8f..2380347 100644
---- a/net/core/pktgen.c
-+++ b/net/core/pktgen.c
-@@ -2582,7 +2582,7 @@ static __inline__ void pktgen_xmit(struc
- }
- }
-
-- spin_lock_bh(&odev->xmit_lock);
-+ netif_tx_lock_bh(odev);
- if (!netif_queue_stopped(odev)) {
-
- atomic_inc(&(pkt_dev->skb->users));
-@@ -2627,7 +2627,7 @@ retry_now:
- 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)) {
-diff --git a/net/core/skbuff.c b/net/core/skbuff.c
-index 2144952..46f56af 100644
---- a/net/core/skbuff.c
-+++ b/net/core/skbuff.c
-@@ -164,9 +164,9 @@ struct sk_buff *__alloc_skb(unsigned int
- 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,8 +230,9 @@ struct sk_buff *alloc_skb_from_cache(kme
-
- 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)->gso_size = 0;
-+ skb_shinfo(skb)->gso_segs = 0;
-+ skb_shinfo(skb)->gso_type = 0;
- skb_shinfo(skb)->frag_list = NULL;
- out:
- return skb;
-@@ -501,8 +502,9 @@ #endif
- 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)->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;
- }
-
- /**
-@@ -1777,6 +1779,133 @@ int skb_append_datato_frags(struct sock
- 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",
-diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
-index 44bda85..2e3323a 100644
---- a/net/decnet/dn_nsp_in.c
-+++ b/net/decnet/dn_nsp_in.c
-@@ -801,8 +801,7 @@ got_it:
- * 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;
- }
-
-diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
-index 3407f19..a0a25e0 100644
---- a/net/decnet/dn_route.c
-+++ b/net/decnet/dn_route.c
-@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, st
- 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) {
-diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
-index 97c276f..5ba719e 100644
---- a/net/ipv4/af_inet.c
-+++ b/net/ipv4/af_inet.c
-@@ -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 @@ int inet_sk_rebuild_header(struct sock *
-
- 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 @@ #endif
- 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 int ipv4_proc_init(void);
- 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)
-diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
-index 8dcba38..19c3c73 100644
---- a/net/ipv4/ip_output.c
-+++ b/net/ipv4/ip_output.c
-@@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined
- 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 @@ packet_routed:
- }
-
- 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 @@ static inline int ip_ufo_append_data(str
- (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 @@ int ip_append_data(struct sock *sk,
- */
- if (transhdrlen &&
- length + fragheaderlen <= mtu &&
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|