Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  RDMA/cxgb3: Wrap the software send queue pointer as needed on flush
  IB/ipath: Change ipath_devdata.ipath_sdma_status to be unsigned long
  IB/ipath: Make ipath_portdata work with struct pid * not pid_t
  IB/ipath: Fix RDMA read response sequence checking
  IB/ipath: Fix many locking issues when switching to error state
  IB/ipath: Fix RC and UC error handling
  RDMA/nes: Fix up nes_lro_max_aggr module parameter
diff --git a/Documentation/cgroups.txt b/Documentation/cgroups.txt
index c298a66..824fc02 100644
--- a/Documentation/cgroups.txt
+++ b/Documentation/cgroups.txt
@@ -310,8 +310,8 @@
   cd /dev/cgroup
   mkdir Charlie
   cd Charlie
-  /bin/echo 2-3 > cpus
-  /bin/echo 1 > mems
+  /bin/echo 2-3 > cpuset.cpus
+  /bin/echo 1 > cpuset.mems
   /bin/echo $$ > tasks
   sh
   # The subshell 'sh' is now running in cgroup Charlie
diff --git a/Documentation/hwmon/adt7473 b/Documentation/hwmon/adt7473
index 22d8b19..2126de3 100644
--- a/Documentation/hwmon/adt7473
+++ b/Documentation/hwmon/adt7473
@@ -69,7 +69,8 @@
 
 The ADT7473 will scale the pwm between the lower and higher pwm speed when
 the temperature is between the two temperature boundaries.  PWM values range
-from 0 (off) to 255 (full speed).
+from 0 (off) to 255 (full speed).  Fan speed will be set to maximum when the
+temperature sensor associated with the PWM control exceeds temp#_max.
 
 Notes
 -----
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index e5a819a..f5b7127 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -994,7 +994,17 @@
 	DATA DEPENDENCY	read_barrier_depends()	smp_read_barrier_depends()
 
 
-All CPU memory barriers unconditionally imply compiler barriers.
+All memory barriers except the data dependency barriers imply a compiler
+barrier. Data dependencies do not impose any additional compiler ordering.
+
+Aside: In the case of data dependencies, the compiler would be expected to
+issue the loads in the correct order (eg. `a[b]` would have to load the value
+of b before loading a[b]), however there is no guarantee in the C specification
+that the compiler may not speculate the value of b (eg. is equal to 1) and load
+a before b (eg. tmp = a[1]; if (b != 1) tmp = a[b]; ). There is also the
+problem of a compiler reloading b after having loaded a[b], thus having a newer
+copy of b than a[b]. A consensus has not yet been reached about these problems,
+however the ACCESS_ONCE macro is a good place to start looking.
 
 SMP memory barriers are reduced to compiler barriers on uniprocessor compiled
 systems because it is assumed that a CPU will appear to be self-consistent,
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 929b90c..191194e 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -5,6 +5,6 @@
   4 -> DViCO FusionHDTV5 Express                           [18ac:d500]
   5 -> Hauppauge WinTV-HVR1500Q                            [0070:7790,0070:7797]
   6 -> Hauppauge WinTV-HVR1500                             [0070:7710,0070:7717]
-  7 -> Hauppauge WinTV-HVR1200                             [0070:71d1]
+  7 -> Hauppauge WinTV-HVR1200                             [0070:71d1,0070:71d3]
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index f40e092..1d6a245 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -14,4 +14,4 @@
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
  14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
- 16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513]
+ 16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513,2040:6517,2040:651b,2040:651f]
diff --git a/MAINTAINERS b/MAINTAINERS
index f5583dc..bc1c008 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -367,12 +367,12 @@
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 P:	Thomas Dahlmann
 M:	thomas.dahlmann@amd.com
-L:	info-linux@geode.amd.com	(subscribers-only)
+L:	linux-geode@lists.infradead.org (moderated for non-subscribers)
 S:	Supported
 
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:	Jordan Crouse
-L:	info-linux@geode.amd.com	(subscribers-only)
+L:	linux-geode@lists.infradead.org (moderated for non-subscribers)
 W:	http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:	Supported
 
@@ -1230,6 +1230,15 @@
 M:	jayakumar.alsa@gmail.com
 S:	Maintained
 
+CX18 VIDEO4LINUX DRIVER
+P:	Hans Verkuil, Andy Walls
+M:	hverkuil@xs4all.nl, awalls@radix.net
+L:	ivtv-devel@ivtvdriver.org
+L:	ivtv-users@ivtvdriver.org
+L:	video4linux-list@redhat.com
+W:	http://linuxtv.org
+S:	Maintained
+
 CYBERPRO FB DRIVER
 P:	Russell King
 M:	rmk@arm.linux.org.uk
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 07eb4c4..8e84415 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -671,6 +671,9 @@
 
 endchoice
 
+if COLDFIRE
+source "kernel/Kconfig.preempt"
+endif
 source "mm/Kconfig"
 
 endmenu
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 5592e0b..93e69236 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -114,6 +114,16 @@
 		*(__kcrctab_gpl)
 		__stop___kcrctab_gpl = .;
 
+		/* Kernel symbol table: Normal unused symbols */
+		__start___kcrctab_unused = .;
+		*(__kcrctab_unused)
+		__stop___kcrctab_unused = .;
+
+		/* Kernel symbol table: GPL-only unused symbols */
+		__start___kcrctab_unused_gpl = .;
+		*(__kcrctab_unused_gpl)
+		__stop___kcrctab_unused_gpl = .;
+
 		/* Kernel symbol table: GPL-future symbols */
 		__start___kcrctab_gpl_future = .;
 		*(__kcrctab_gpl_future)
diff --git a/arch/mn10300/boot/install.sh b/arch/mn10300/boot/install.sh
index 072951c..abba309 100644
--- a/arch/mn10300/boot/install.sh
+++ b/arch/mn10300/boot/install.sh
@@ -26,42 +26,42 @@
 install -c -m 0755 $2 $4/vmlinuz
 install -c -m 0755 $5 $4/boot.rom
 install -c -m 0755 -d $4/../usr/include/linux
-cd $TOPDIR/include/linux
+cd ${srctree}/include/linux
 for i in `find . -maxdepth 1 -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux
 done
 install -c -m 0755 -d $4/../usr/include/linux/byteorder
-cd $TOPDIR/include/linux/byteorder
+cd ${srctree}/include/linux/byteorder
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/byteorder
 done
 install -c -m 0755 -d $4/../usr/include/linux/lockd
-cd $TOPDIR/include/linux/lockd
+cd ${srctree}/include/linux/lockd
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/lockd
 done
 install -c -m 0755 -d $4/../usr/include/linux/netfilter_ipv4
-cd $TOPDIR/include/linux/netfilter_ipv4
+cd ${srctree}/include/linux/netfilter_ipv4
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/netfilter_ipv4
 done
 install -c -m 0755 -d $4/../usr/include/linux/nfsd
-cd $TOPDIR/include/linux/nfsd
+cd ${srctree}/include/linux/nfsd
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/nfsd/$i
 done
 install -c -m 0755 -d $4/../usr/include/linux/raid
-cd $TOPDIR/include/linux/raid
+cd ${srctree}/include/linux/raid
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/raid
 done
 install -c -m 0755 -d $4/../usr/include/linux/sunrpc
-cd $TOPDIR/include/linux/sunrpc
+cd ${srctree}/include/linux/sunrpc
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/linux/sunrpc
 done
 install -c -m 0755 -d $4/../usr/include/asm
-cd $TOPDIR/include/asm
+cd ${srctree}/include/asm
 for i in `find . -name '*.h' -print`; do
   install -c -m 0644 $i $4/../usr/include/asm
 done
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 1f01284..b0ed709 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -606,7 +606,7 @@
 		int i, j;
 
 		for (i = 0; i < npmem_ranges; i++) {
-			zl = node_zonelist(i);
+			zl = node_zonelist(i, 0);
 			for (j = 0; j < MAX_NR_ZONES; j++) {
 				struct zoneref *z;
 				struct zone *zone;
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 3a4b396..1b238eb 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -145,14 +145,14 @@
 	  systems, it is safe to say N.
 
 config RAW_DRIVER
-        tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
+        tristate "RAW driver (/dev/raw/rawN)"
+	depends on BLOCK
         help
           The raw driver permits block devices to be bound to /dev/raw/rawN.
           Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
           See the raw(8) manpage for more details.
 
-          The raw driver is deprecated and will be removed soon.
-          Applications should simply open the device (eg /dev/hda1)
+          Applications should preferably open the device (eg /dev/hda1)
           with the O_DIRECT flag.
 
 config MAX_RAW_DEVS
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 0257640..cfeb3f4 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -11,6 +11,7 @@
 #include <termios.h>
 #include <sys/ioctl.h>
 #include "chan_user.h"
+#include "kern_constants.h"
 #include "os.h"
 #include "um_malloc.h"
 #include "user.h"
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index ca8c9e1..f5701fd 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -8,7 +8,7 @@
 
 static inline void *cow_malloc(int size)
 {
-	return kmalloc(size, UM_GFP_KERNEL);
+	return uml_kmalloc(size, UM_GFP_KERNEL);
 }
 
 static inline void cow_free(void *ptr)
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index f23c109..f8e85e0 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -34,7 +34,7 @@
 {
 	struct sockaddr_un *sun;
 
-	sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
+	sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
 	if (sun == NULL) {
 		printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un "
 		       "failed\n");
@@ -83,7 +83,7 @@
 		goto out_close;
 	}
 
-	sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
+	sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
 	if (sun == NULL) {
 		printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un "
 		       "failed\n");
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 0a2bb5b..f5a981a 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -40,7 +40,7 @@
 		return NULL;
 	}
 
-	data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
 	if (data == NULL)
 		return NULL;
 
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index ff1b22b..368219c 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -154,7 +154,7 @@
 	case SNDCTL_DSP_SUBDIVIDE:
 	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(data, (int __user *) arg))
-			return EFAULT;
+			return -EFAULT;
 		break;
 	default:
 		break;
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index 5f647d7..ee19e91 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -15,6 +15,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <netinet/in.h>
+#include "kern_constants.h"
 #include "mcast.h"
 #include "net_user.h"
 #include "um_malloc.h"
@@ -24,7 +25,7 @@
 {
 	struct sockaddr_in *sin;
 
-	sin = kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
+	sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
 	if (sin == NULL) {
 		printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
 		       "failed\n");
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index abf2653..9415dd9 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -222,7 +222,7 @@
 		netmask[2], netmask[3]);
 
 	output_len = UM_KERN_PAGE_SIZE;
-	output = kmalloc(output_len, UM_GFP_KERNEL);
+	output = uml_kmalloc(output_len, UM_GFP_KERNEL);
 	if (output == NULL)
 		printk(UM_KERN_ERR "change : failed to allocate output "
 		       "buffer\n");
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index d269ca3..b49bf56 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -47,7 +47,7 @@
 	if (kern_data == NULL)
 		return NULL;
 
-	data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
 	if (data == NULL)
 		goto err;
 
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 49c79dd..1113911 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -29,7 +29,7 @@
 {
 	struct pty_chan *data;
 
-	data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
 	if (data == NULL)
 		return NULL;
 
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index 71f0959..4949044 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */
+/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
+
 /* Much of this ripped from drivers/char/hw_random.c, see there for other
  * copyright.
  *
@@ -8,16 +9,18 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
+#include "irq_kern.h"
 #include "os.h"
 
 /*
  * core module and version information
  */
 #define RNG_VERSION "1.0.0"
-#define RNG_MODULE_NAME "random"
+#define RNG_MODULE_NAME "hw_random"
 
 #define RNG_MISCDEV_MINOR		183 /* official */
 
@@ -26,47 +29,67 @@
  * protects against a module being loaded twice at the same time.
  */
 static int random_fd = -1;
+static DECLARE_WAIT_QUEUE_HEAD(host_read_wait);
 
 static int rng_dev_open (struct inode *inode, struct file *filp)
 {
 	/* enforce read-only access to this chrdev */
 	if ((filp->f_mode & FMODE_READ) == 0)
 		return -EINVAL;
-	if (filp->f_mode & FMODE_WRITE)
+	if ((filp->f_mode & FMODE_WRITE) != 0)
 		return -EINVAL;
 
 	return 0;
 }
 
+static atomic_t host_sleep_count = ATOMIC_INIT(0);
+
 static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
-                             loff_t * offp)
+			     loff_t *offp)
 {
-        u32 data;
-        int n, ret = 0, have_data;
+	u32 data;
+	int n, ret = 0, have_data;
 
-        while(size){
-                n = os_read_file(random_fd, &data, sizeof(data));
-                if(n > 0){
-                        have_data = n;
-                        while (have_data && size) {
-                                if (put_user((u8)data, buf++)) {
-                                        ret = ret ? : -EFAULT;
-                                        break;
-                                }
-                                size--;
-                                ret++;
-                                have_data--;
-                                data>>=8;
-                        }
-                }
-                else if(n == -EAGAIN){
-                        if (filp->f_flags & O_NONBLOCK)
-                                return ret ? : -EAGAIN;
+	while (size) {
+		n = os_read_file(random_fd, &data, sizeof(data));
+		if (n > 0) {
+			have_data = n;
+			while (have_data && size) {
+				if (put_user((u8) data, buf++)) {
+					ret = ret ? : -EFAULT;
+					break;
+				}
+				size--;
+				ret++;
+				have_data--;
+				data >>= 8;
+			}
+		}
+		else if (n == -EAGAIN) {
+			DECLARE_WAITQUEUE(wait, current);
 
-                        if(need_resched())
-                                schedule_timeout_interruptible(1);
-                }
-                else return n;
+			if (filp->f_flags & O_NONBLOCK)
+				return ret ? : -EAGAIN;
+
+			atomic_inc(&host_sleep_count);
+			reactivate_fd(random_fd, RANDOM_IRQ);
+			add_sigio_fd(random_fd);
+
+			add_wait_queue(&host_read_wait, &wait);
+			set_task_state(current, TASK_INTERRUPTIBLE);
+
+			schedule();
+			set_task_state(current, TASK_RUNNING);
+			remove_wait_queue(&host_read_wait, &wait);
+
+			if (atomic_dec_and_test(&host_sleep_count)) {
+				ignore_sigio_fd(random_fd);
+				deactivate_fd(random_fd, RANDOM_IRQ);
+			}
+		}
+		else
+			return n;
+
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
 	}
@@ -86,6 +109,13 @@
 	&rng_chrdev_ops,
 };
 
+static irqreturn_t random_interrupt(int irq, void *data)
+{
+	wake_up(&host_read_wait);
+
+	return IRQ_HANDLED;
+}
+
 /*
  * rng_init - initialize RNG module
  */
@@ -93,28 +123,33 @@
 {
 	int err;
 
-        err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
-        if(err < 0)
-                goto out;
+	err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
+	if (err < 0)
+		goto out;
 
-        random_fd = err;
+	random_fd = err;
 
-        err = os_set_fd_block(random_fd, 0);
-        if(err)
+	err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
+			     IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "random",
+			     NULL);
+	if (err)
 		goto err_out_cleanup_hw;
 
+	sigio_broken(random_fd, 1);
+
 	err = misc_register (&rng_miscdev);
 	if (err) {
-		printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n");
+		printk (KERN_ERR RNG_MODULE_NAME ": misc device register "
+			"failed\n");
 		goto err_out_cleanup_hw;
 	}
+out:
+	return err;
 
- out:
-        return err;
-
- err_out_cleanup_hw:
-        random_fd = -1;
-        goto out;
+err_out_cleanup_hw:
+	os_close_file(random_fd);
+	random_fd = -1;
+	goto out;
 }
 
 /*
@@ -122,6 +157,7 @@
  */
 static void __exit rng_cleanup (void)
 {
+	os_close_file(random_fd);
 	misc_deregister (&rng_miscdev);
 }
 
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 8b80505..a1c2d2c 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -96,7 +96,7 @@
 	pid = err;
 
 	output_len = UM_KERN_PAGE_SIZE;
-	output = kmalloc(output_len, UM_GFP_KERNEL);
+	output = uml_kmalloc(output_len, UM_GFP_KERNEL);
 	if (output == NULL) {
 		printk(UM_KERN_ERR "slip_tramp : failed to allocate output "
 		       "buffer\n");
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index c930fed..495858a 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -29,7 +29,7 @@
 	}
 	str++;
 
-	data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
 	if (data == NULL)
 		return NULL;
 	*data = ((struct tty_chan) { .dev 	= str,
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 5e45e39..44ad160 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -1178,8 +1178,8 @@
 	 * by one word.  Thanks to Lynn Kerby for the fix and James McMechan
 	 * for the original diagnosis.
 	 */
-	if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
-			   sizeof(unsigned long) - 1))
+	if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
+					 sizeof(unsigned long)) - 1))
 		(*cow_offset)--;
 
 	bitmap_words[0] = bitmap[*cow_offset];
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 8a1c18a..da2caa5 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -30,7 +30,7 @@
 {
 	struct xterm_chan *data;
 
-	data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
 	if (data == NULL)
 		return NULL;
 	*data = ((struct xterm_chan) { .pid 		= -1,
diff --git a/arch/um/include/as-layout.h b/arch/um/include/as-layout.h
index cac542d..58e852d 100644
--- a/arch/um/include/as-layout.h
+++ b/arch/um/include/as-layout.h
@@ -23,16 +23,16 @@
  */
 
 #ifdef __ASSEMBLY__
-#define _AC(X, Y)	(Y)
+#define _UML_AC(X, Y)	(Y)
 #else
-#define __AC(X, Y)	(X (Y))
-#define _AC(X, Y)	__AC(X, Y)
+#define __UML_AC(X, Y)	(X(Y))
+#define _UML_AC(X, Y)	__UML_AC(X, Y)
 #endif
 
-#define STUB_START _AC(, 0x100000)
-#define STUB_CODE _AC((unsigned long), STUB_START)
-#define STUB_DATA _AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE)
-#define STUB_END _AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE)
+#define STUB_START _UML_AC(, 0x100000)
+#define STUB_CODE _UML_AC((unsigned long), STUB_START)
+#define STUB_DATA _UML_AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE)
+#define STUB_END _UML_AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE)
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 979b73e..311a0d3 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -58,11 +58,11 @@
 };
 
 #define LINE_INIT(str, d) \
-	{ .count_lock =	SPIN_LOCK_UNLOCKED, \
+	{ .count_lock =	__SPIN_LOCK_UNLOCKED((str).count_lock), \
 	  .init_str =	str,	\
 	  .init_pri =	INIT_STATIC, \
 	  .valid =	1, \
-	  .lock =	SPIN_LOCK_UNLOCKED, \
+	  .lock =	__SPIN_LOCK_UNLOCKED((str).lock), \
 	  .driver =	d }
 
 extern void line_close(struct tty_struct *tty, struct file * filp);
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 32c799e..e2716ac 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -290,6 +290,7 @@
 extern int add_sigio_fd(int fd);
 extern int ignore_sigio_fd(int fd);
 extern void maybe_sigio_broken(int fd, int read);
+extern void sigio_broken(int fd, int read);
 
 /* sys-x86_64/prctl.c */
 extern int os_arch_prctl(int pid, int code, unsigned long *addr);
diff --git a/arch/um/include/process.h b/arch/um/include/process.h
index 5af9157..bb873a5 100644
--- a/arch/um/include/process.h
+++ b/arch/um/include/process.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -8,18 +8,10 @@
 
 #include <signal.h>
 
-extern void sig_handler(int sig, struct sigcontext sc);
-extern void alarm_handler(int sig, struct sigcontext sc);
+/* Copied from linux/compiler-gcc.h since we can't include it directly */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+extern void sig_handler(int sig, struct sigcontext *sc);
+extern void alarm_handler(int sig, struct sigcontext *sc);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h
index cd2327d..3d31bba 100644
--- a/arch/um/include/skas_ptrace.h
+++ b/arch/um/include/skas_ptrace.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -12,14 +12,3 @@
 #include "sysdep/skas_ptrace.h"
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index 7565072..ef56247 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -41,38 +41,10 @@
 #define PT_SP_OFFSET PT_OFFSET(UESP)
 #define PT_SP(regs) ((regs)[UESP])
 
-#define FP_SIZE ((HOST_XFP_SIZE > HOST_FP_SIZE) ? HOST_XFP_SIZE : HOST_FP_SIZE)
+#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE)
 
 #ifndef FRAME_SIZE
 #define FRAME_SIZE (17)
 #endif
-#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
-
-#define FP_FRAME_SIZE (27)
-#define FPX_FRAME_SIZE (128)
-
-#ifdef PTRACE_GETREGS
-#define UM_HAVE_GETREGS
-#endif
-
-#ifdef PTRACE_SETREGS
-#define UM_HAVE_SETREGS
-#endif
-
-#ifdef PTRACE_GETFPREGS
-#define UM_HAVE_GETFPREGS
-#endif
-
-#ifdef PTRACE_SETFPREGS
-#define UM_HAVE_SETFPREGS
-#endif
-
-#ifdef PTRACE_GETFPXREGS
-#define UM_HAVE_GETFPXREGS
-#endif
-
-#ifdef PTRACE_SETFPXREGS
-#define UM_HAVE_SETFPXREGS
-#endif
 
 #endif
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
index 67e7712..f583c87 100644
--- a/arch/um/include/sysdep-i386/sigcontext.h
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -10,7 +10,7 @@
 
 #define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
 
-#define GET_FAULTINFO_FROM_SC(fi,sc) \
+#define GET_FAULTINFO_FROM_SC(fi, sc) \
 	{ \
 		(fi).cr2 = SC_CR2(sc); \
 		(fi).error_code = SC_ERR(sc); \
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 45c0bd8..4dbccdb 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -48,7 +48,8 @@
 #define PT_ORIG_RAX_OFFSET (ORIG_RAX)
 #define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)])
 
-/* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
+/*
+ * x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
  * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the
  * 2.4 name and value for 2.4 host compatibility.
  */
@@ -56,7 +57,8 @@
 #define PTRACE_OLDSETOPTIONS 21
 #endif
 
-/* These are before the system call, so the system call number is RAX
+/*
+ * These are before the system call, so the system call number is RAX
  * rather than ORIG_RAX, and arg4 is R10 rather than RCX
  */
 #define REGS_SYSCALL_NR PT_INDEX(RAX)
@@ -73,14 +75,3 @@
 #define FP_SIZE (HOST_FP_SIZE)
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
index 0ad17cb..c554d70 100644
--- a/arch/um/include/um_malloc.h
+++ b/arch/um/include/um_malloc.h
@@ -8,15 +8,12 @@
 
 #include "kern_constants.h"
 
-extern void *__kmalloc(int size, int flags);
-static inline void *kmalloc(int size, int flags)
-{
-	return __kmalloc(size, flags);
-}
-
+extern void *uml_kmalloc(int size, int flags);
 extern void kfree(const void *ptr);
 
 extern void *vmalloc(unsigned long size);
 extern void vfree(void *ptr);
 
 #endif /* __UM_MALLOC_H__ */
+
+
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 26090b7..9975e1a 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -1,4 +1,5 @@
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 
 OUTPUT_FORMAT(ELF_FORMAT)
 OUTPUT_ARCH(ELF_ARCH)
@@ -21,7 +22,7 @@
 	_einittext = .;
   }
 
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
 
   /* Read-only sections, merged into text segment: */
   .hash           : { *(.hash) }
@@ -68,9 +69,9 @@
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
 
-    . = ALIGN(4096);
+    . = ALIGN(PAGE_SIZE);
   } =0x90909090
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
   .syscall_stub : {
 	__syscall_stub_start = .;
 	*(.__syscall_stub*)
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 2eea1ff..b0ee646 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -375,3 +375,8 @@
 	return pmd;
 }
 #endif
+
+void *uml_kmalloc(int size, int flags)
+{
+	return kmalloc(size, flags);
+}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 0d0cea2..c3e2f36 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -75,7 +75,7 @@
 
 static cycle_t itimer_read(void)
 {
-	return os_nsecs();
+	return os_nsecs() / 1000;
 }
 
 static struct clocksource itimer_clocksource = {
@@ -83,7 +83,7 @@
 	.rating		= 300,
 	.read		= itimer_read,
 	.mask		= CLOCKSOURCE_MASK(64),
-	.mult		= 1,
+	.mult		= 1000,
 	.shift		= 0,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 56deed6..9db85b2 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -150,7 +150,7 @@
 static int __init no_skas_debug_setup(char *line, int *add)
 {
 	printf("'debug' is not necessary to gdb UML in skas mode - run \n");
-	printf("'gdb linux'");
+	printf("'gdb linux'\n");
 
 	return 0;
 }
@@ -258,6 +258,7 @@
 {
 	unsigned long avail, diff;
 	unsigned long virtmem_size, max_physmem;
+	unsigned long stack;
 	unsigned int i;
 	int add;
 	char * mode;
@@ -348,7 +349,9 @@
 	}
 
 	virtmem_size = physmem_size;
-	avail = TASK_SIZE - start_vm;
+	stack = (unsigned long) argv;
+	stack &= ~(1024 * 1024 - 1);
+	avail = stack - start_vm;
 	if (physmem_size > avail)
 		virtmem_size = avail;
 	end_vm = start_vm + virtmem_size;
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 5828c1d..11b8352 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -1,4 +1,5 @@
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 
 OUTPUT_FORMAT(ELF_FORMAT)
 OUTPUT_ARCH(ELF_ARCH)
@@ -26,7 +27,7 @@
 	INIT_TEXT
 	_einittext = .;
   }
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
 
   .text      :
   {
@@ -39,7 +40,7 @@
     *(.gnu.linkonce.t*)
   }
 
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE);
   .syscall_stub : {
 	__syscall_stub_start = .;
 	*(.__syscall_stub*)
@@ -79,7 +80,7 @@
   .sdata     : { *(.sdata) }
   _edata  =  .;
   PROVIDE (edata = .);
-  . = ALIGN(0x1000);
+  . = ALIGN(PAGE_SIZE);
   .sbss      :
   {
    __bss_start = .;
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index 6fb0b17..cc72cb2 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -52,7 +52,7 @@
 		return;
 	}
 
-	output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
+	output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
 	if (output == NULL)
 		printk(UM_KERN_ERR "etap_change : Failed to allocate output "
 		       "buffer\n");
@@ -165,7 +165,7 @@
 	err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
 			 control_fds[1], data_fds[0], data_fds[1]);
 	output_len = UM_KERN_PAGE_SIZE;
-	output = kmalloc(output_len, UM_GFP_KERNEL);
+	output = uml_kmalloc(output_len, UM_GFP_KERNEL);
 	read_output(control_fds[0], output, output_len);
 
 	if (output == NULL)
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index f25c29a..74ca7aa 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -71,8 +71,8 @@
 	data.pre_data = pre_data;
 	data.argv = argv;
 	data.fd = fds[1];
-	data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
-					kmalloc(PATH_MAX, UM_GFP_KERNEL);
+	data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
+					uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
 	pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
 	if (pid < 0) {
 		ret = -errno;
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index abb9b0f..eee69b9 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -199,7 +199,7 @@
 		return __real_malloc(size);
 	else if (size <= UM_KERN_PAGE_SIZE)
 		/* finding contiguous pages can be hard*/
-		ret = kmalloc(size, UM_GFP_KERNEL);
+		ret = uml_kmalloc(size, UM_GFP_KERNEL);
 	else ret = vmalloc(size);
 
 	/*
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index abf47a7c..eb8f2e4 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -15,6 +15,7 @@
 #include "kern_util.h"
 #include "init.h"
 #include "os.h"
+#include "process.h"
 #include "sigio.h"
 #include "um_malloc.h"
 #include "user.h"
@@ -109,7 +110,7 @@
 	if (n <= polls->size)
 		return 0;
 
-	new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
+	new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
 	if (new == NULL) {
 		printk(UM_KERN_ERR "need_poll : failed to allocate new "
 		       "pollfds\n");
@@ -243,7 +244,7 @@
 {
 	struct pollfd *p;
 
-	p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
+	p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
 	if (p == NULL) {
 		printk(UM_KERN_ERR "setup_initial_poll : failed to allocate "
 		       "poll\n");
@@ -338,20 +339,10 @@
 	close(l_write_sigio_fds[1]);
 }
 
-/* Changed during early boot */
-static int pty_output_sigio = 0;
-static int pty_close_sigio = 0;
-
-void maybe_sigio_broken(int fd, int read)
+void sigio_broken(int fd, int read)
 {
 	int err;
 
-	if (!isatty(fd))
-		return;
-
-	if ((read || pty_output_sigio) && (!read || pty_close_sigio))
-		return;
-
 	write_sigio_workaround();
 
 	sigio_lock();
@@ -370,6 +361,21 @@
 	sigio_unlock();
 }
 
+/* Changed during early boot */
+static int pty_output_sigio;
+static int pty_close_sigio;
+
+void maybe_sigio_broken(int fd, int read)
+{
+	if (!isatty(fd))
+		return;
+
+	if ((read || pty_output_sigio) && (!read || pty_close_sigio))
+		return;
+
+	sigio_broken(fd, read);
+}
+
 static void sigio_cleanup(void)
 {
 	if (write_sigio_pid == -1)
@@ -383,7 +389,7 @@
 __uml_exitcall(sigio_cleanup);
 
 /* Used as a flag during SIGIO testing early in boot */
-static volatile int got_sigio = 0;
+static int got_sigio;
 
 static void __init handler(int sig)
 {
@@ -498,7 +504,8 @@
 	if (errno != EAGAIN)
 		printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n",
 		       errno);
-	while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio)
+	while (((n = read(slave, buf, sizeof(buf))) > 0) &&
+	       !({ barrier(); got_sigio; }))
 		;
 
 	if (got_sigio) {
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 3f1694b..5aade60 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -12,6 +12,7 @@
 #include "as-layout.h"
 #include "kern_util.h"
 #include "os.h"
+#include "process.h"
 #include "sysdep/barrier.h"
 #include "sysdep/sigcontext.h"
 #include "user.h"
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 1e8cba6..6be028c 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -442,7 +442,7 @@
 				unblock_signals();
 				break;
 			default:
-			        printk(UM_KERN_ERR "userspace - child stopped "
+				printk(UM_KERN_ERR "userspace - child stopped "
 				       "with signal %d\n", sig);
 				fatal_sigsegv();
 			}
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 997d019..b4b36e0 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -23,6 +23,7 @@
 #include "mem_user.h"
 #include "ptrace_user.h"
 #include "registers.h"
+#include "skas.h"
 #include "skas_ptrace.h"
 
 static void ptrace_child(void)
@@ -140,14 +141,27 @@
 }
 
 /* Changed only during early boot */
-int ptrace_faultinfo = 1;
-int ptrace_ldt = 1;
-int proc_mm = 1;
-int skas_needs_stub = 0;
+int ptrace_faultinfo;
+static int disable_ptrace_faultinfo;
+
+int ptrace_ldt;
+static int disable_ptrace_ldt;
+
+int proc_mm;
+static int disable_proc_mm;
+
+int have_switch_mm;
+static int disable_switch_mm;
+
+int skas_needs_stub;
 
 static int __init skas0_cmd_param(char *str, int* add)
 {
-	ptrace_faultinfo = proc_mm = 0;
+	disable_ptrace_faultinfo = 1;
+	disable_ptrace_ldt = 1;
+	disable_proc_mm = 1;
+	disable_switch_mm = 1;
+
 	return 0;
 }
 
@@ -157,15 +171,12 @@
 	__attribute__((alias("skas0_cmd_param")));
 
 __uml_setup("skas0", skas0_cmd_param,
-		"skas0\n"
-		"    Disables SKAS3 usage, so that SKAS0 is used, unless \n"
-	        "    you specify mode=tt.\n\n");
+"skas0\n"
+"    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n");
 
 __uml_setup("mode=skas0", mode_skas0_cmd_param,
-		"mode=skas0\n"
-		"    Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
-		"    specify mode=tt. Note that this was recently added - on \n"
-		"    older kernels you must use simply \"skas0\".\n\n");
+"mode=skas0\n"
+"    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n");
 
 /* Changed only during early boot */
 static int force_sysemu_disabled = 0;
@@ -360,7 +371,7 @@
 
 static int __init noprocmm_cmd_param(char *str, int* add)
 {
-	proc_mm = 0;
+	disable_proc_mm = 1;
 	return 0;
 }
 
@@ -372,7 +383,7 @@
 
 static int __init noptracefaultinfo_cmd_param(char *str, int* add)
 {
-	ptrace_faultinfo = 0;
+	disable_ptrace_faultinfo = 1;
 	return 0;
 }
 
@@ -384,7 +395,7 @@
 
 static int __init noptraceldt_cmd_param(char *str, int* add)
 {
-	ptrace_ldt = 0;
+	disable_ptrace_ldt = 1;
 	return 0;
 }
 
@@ -404,17 +415,15 @@
 
 	n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
 	if (n < 0) {
-		ptrace_faultinfo = 0;
 		if (errno == EIO)
 			non_fatal("not found\n");
 		else
 			perror("not found");
-	}
+	} else if (disable_ptrace_faultinfo)
+		non_fatal("found but disabled on command line\n");
 	else {
-		if (!ptrace_faultinfo)
-			non_fatal("found but disabled on command line\n");
-		else
-			non_fatal("found\n");
+		ptrace_faultinfo = 1;
+		non_fatal("found\n");
 	}
 
 	stop_ptraced_child(pid, 1, 1);
@@ -437,38 +446,30 @@
 	if (n < 0) {
 		if (errno == EIO)
 			non_fatal("not found\n");
-		else {
-			perror("not found");
-		}
-		ptrace_ldt = 0;
-	}
-	else {
-		if (ptrace_ldt)
-			non_fatal("found\n");
 		else
-			non_fatal("found, but use is disabled\n");
+			perror("not found");
+	} else if (disable_ptrace_ldt)
+		non_fatal("found, but use is disabled\n");
+	else {
+		ptrace_ldt = 1;
+		non_fatal("found\n");
 	}
 
 	stop_ptraced_child(pid, 1, 1);
-#else
-	/* PTRACE_LDT might be disabled via cmdline option.
-	 * We want to override this, else we might use the stub
-	 * without real need
-	 */
-	ptrace_ldt = 1;
 #endif
 }
 
 static inline void check_skas3_proc_mm(void)
 {
 	non_fatal("  - /proc/mm...");
-	if (access("/proc/mm", W_OK) < 0) {
-		proc_mm = 0;
+	if (access("/proc/mm", W_OK) < 0)
 		perror("not found");
-	}
-	else if (!proc_mm)
+	else if (disable_proc_mm)
 		non_fatal("found but disabled on command line\n");
-	else non_fatal("found\n");
+	else {
+		proc_mm = 1;
+		non_fatal("found\n");
+	}
 }
 
 void can_do_skas(void)
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index b613473..c6183e7 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -5,6 +5,7 @@
  */
 
 #include <errno.h>
+#include <asm/user.h>
 #include "kern_constants.h"
 #include "longjmp.h"
 #include "user.h"
@@ -74,10 +75,10 @@
 
 void arch_init_registers(int pid)
 {
-	unsigned long fpx_regs[HOST_XFP_SIZE];
+	struct user_fxsr_struct fpx_regs;
 	int err;
 
-	err = ptrace(PTRACE_GETFPXREGS, pid, 0, fpx_regs);
+	err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
 	if (!err)
 		return;
 
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index e492805..bee98f4 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -9,7 +9,9 @@
 #include <time.h>
 #include <sys/time.h>
 #include "kern_constants.h"
+#include "kern_util.h"
 #include "os.h"
+#include "process.h"
 #include "user.h"
 
 int set_interval(void)
@@ -58,12 +60,17 @@
 long long disable_timer(void)
 {
 	struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
+	int remain, max = UM_NSEC_PER_SEC / UM_HZ;
 
 	if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
 		printk(UM_KERN_ERR "disable_timer - setitimer failed, "
 		       "errno = %d\n", errno);
 
-	return timeval_to_ns(&time.it_value);
+	remain = timeval_to_ns(&time.it_value);
+	if (remain > max)
+		remain = max;
+
+	return remain;
 }
 
 long long os_nsecs(void)
@@ -79,7 +86,44 @@
 {
 	return 0;
 }
+
+static void deliver_alarm(void)
+{
+	alarm_handler(SIGVTALRM, NULL);
+}
+
+static unsigned long long sleep_time(unsigned long long nsecs)
+{
+	return nsecs;
+}
+
 #else
+unsigned long long last_tick;
+unsigned long long skew;
+
+static void deliver_alarm(void)
+{
+	unsigned long long this_tick = os_nsecs();
+	int one_tick = UM_NSEC_PER_SEC / UM_HZ;
+
+	if (last_tick == 0)
+		last_tick = this_tick - one_tick;
+
+	skew += this_tick - last_tick;
+
+	while (skew >= one_tick) {
+		alarm_handler(SIGVTALRM, NULL);
+		skew -= one_tick;
+	}
+
+	last_tick = this_tick;
+}
+
+static unsigned long long sleep_time(unsigned long long nsecs)
+{
+	return nsecs > skew ? nsecs - skew : 0;
+}
+
 static inline long long timespec_to_us(const struct timespec *ts)
 {
 	return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
@@ -102,6 +146,8 @@
 	 */
 	if (start_usecs > usec)
 		start_usecs = usec;
+
+	start_usecs -= skew / UM_NSEC_PER_USEC;
 	tv = ((struct timeval) { .tv_sec  = start_usecs / UM_USEC_PER_SEC,
 				 .tv_usec = start_usecs % UM_USEC_PER_SEC });
 	interval = ((struct itimerval) { { 0, usec }, tv });
@@ -113,8 +159,6 @@
 }
 #endif
 
-extern void alarm_handler(int sig, struct sigcontext *sc);
-
 void idle_sleep(unsigned long long nsecs)
 {
 	struct timespec ts;
@@ -126,10 +170,12 @@
 	 */
 	if (nsecs == 0)
 		nsecs = UM_NSEC_PER_SEC / UM_HZ;
+
+	nsecs = sleep_time(nsecs);
 	ts = ((struct timespec) { .tv_sec	= nsecs / UM_NSEC_PER_SEC,
 				  .tv_nsec	= nsecs % UM_NSEC_PER_SEC });
 
 	if (nanosleep(&ts, &ts) == 0)
-		alarm_handler(SIGVTALRM, NULL);
+		deliver_alarm();
 	after_sleep_interval(&ts);
 }
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index 6b44999..c9b1765 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -148,14 +148,13 @@
 int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 {
 	int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
-	long fpregs[HOST_FP_SIZE];
+	struct user_i387_struct fpregs;
 
-	BUG_ON(sizeof(*buf) != sizeof(fpregs));
-	err = save_fp_registers(userspace_pid[cpu], fpregs);
+	err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
 	if (err)
 		return err;
 
-	n = copy_to_user(buf, fpregs, sizeof(fpregs));
+	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
 	if(n > 0)
 		return -EFAULT;
 
@@ -165,27 +164,26 @@
 int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 {
 	int n, cpu = ((struct thread_info *) child->stack)->cpu;
-	long fpregs[HOST_FP_SIZE];
+	struct user_i387_struct fpregs;
 
-	BUG_ON(sizeof(*buf) != sizeof(fpregs));
-	n = copy_from_user(fpregs, buf, sizeof(fpregs));
+	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
 	if (n > 0)
 		return -EFAULT;
 
-	return restore_fp_registers(userspace_pid[cpu], fpregs);
+	return restore_fp_registers(userspace_pid[cpu],
+				    (unsigned long *) &fpregs);
 }
 
 int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
 {
 	int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
-	long fpregs[HOST_XFP_SIZE];
+	struct user_fxsr_struct fpregs;
 
-	BUG_ON(sizeof(*buf) != sizeof(fpregs));
-	err = save_fpx_registers(userspace_pid[cpu], fpregs);
+	err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
 	if (err)
 		return err;
 
-	n = copy_to_user(buf, fpregs, sizeof(fpregs));
+	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
 	if(n > 0)
 		return -EFAULT;
 
@@ -195,14 +193,14 @@
 int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
 {
 	int n, cpu = ((struct thread_info *) child->stack)->cpu;
-	long fpregs[HOST_XFP_SIZE];
+	struct user_fxsr_struct fpregs;
 
-	BUG_ON(sizeof(*buf) != sizeof(fpregs));
-	n = copy_from_user(fpregs, buf, sizeof(fpregs));
+	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
 	if (n > 0)
 		return -EFAULT;
 
-	return restore_fpx_registers(userspace_pid[cpu], fpregs);
+	return restore_fpx_registers(userspace_pid[cpu],
+				     (unsigned long *) &fpregs);
 }
 
 long subarch_ptrace(struct task_struct *child, long request, long addr,
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
index 39bd32b..5f883bf 100644
--- a/arch/um/sys-i386/user-offsets.c
+++ b/arch/um/sys-i386/user-offsets.c
@@ -22,7 +22,7 @@
 	OFFSET(HOST_SC_CR2, sigcontext, cr2);
 
 	DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_fpregs_struct));
-	DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fpxregs_struct));
+	DEFINE_LONGS(HOST_FPX_SIZE, sizeof(struct user_fpxregs_struct));
 
 	DEFINE(HOST_IP, EIP);
 	DEFINE(HOST_SP, UESP);
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c
index 2f3443c..9735854 100644
--- a/arch/um/sys-x86_64/user-offsets.c
+++ b/arch/um/sys-x86_64/user-offsets.c
@@ -24,7 +24,6 @@
 	OFFSET(HOST_SC_TRAPNO, sigcontext, trapno);
 
 	DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long));
-	DEFINE(HOST_XFP_SIZE, 0);
 	DEFINE_LONGS(HOST_RBX, RBX);
 	DEFINE_LONGS(HOST_RCX, RCX);
 	DEFINE_LONGS(HOST_RDI, RDI);
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
index 22fab6c..7da00b7 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -12,11 +12,6 @@
 
 SECTIONS
 {
-	. = HEADER_OFFSET;
-	.header : {
-		 *(.header)
-	}
-
 	. = 0;
 	.text : {
 		 *(.text*)
@@ -50,6 +45,11 @@
 		__bss_end = .;
 	}
 
+	. = HEADER_OFFSET;
+	.header : {
+		*(.header)
+	}
+
 	. = ALIGN(16);
 	_end = .;
 
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 0c37f16..c5ef1af 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -385,11 +385,13 @@
 	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
 		return memory;
 
-	if (!dev)
+	if (!dev) {
 		dev = &fallback_dev;
+		gfp |= GFP_DMA;
+	}
 	dma_mask = dev->coherent_dma_mask;
 	if (dma_mask == 0)
-		dma_mask = DMA_32BIT_MASK;
+		dma_mask = (gfp & GFP_DMA) ? DMA_24BIT_MASK : DMA_32BIT_MASK;
 
 	/* Device not DMA able */
 	if (dev->dma_mask == NULL)
@@ -403,7 +405,7 @@
 	   larger than 16MB and in this case we have a chance of
 	   finding fitting memory in the next higher zone first. If
 	   not retry with true GFP_DMA. -AK */
-	if (dma_mask <= DMA_32BIT_MASK)
+	if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA))
 		gfp |= GFP_DMA32;
 #endif
 
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index fb03ef3..a7835f2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1303,6 +1303,9 @@
 #define genregs32_get		genregs_get
 #define genregs32_set		genregs_set
 
+#define user_i387_ia32_struct	user_i387_struct
+#define user32_fxsr_struct	user_fxsr_struct
+
 #endif	/* CONFIG_X86_64 */
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@ -1315,13 +1318,13 @@
 	},
 	[REGSET_FP] = {
 		.core_note_type = NT_PRFPREG,
-		.n = sizeof(struct user_i387_struct) / sizeof(u32),
+		.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
 		.size = sizeof(u32), .align = sizeof(u32),
 		.active = fpregs_active, .get = fpregs_get, .set = fpregs_set
 	},
 	[REGSET_XFP] = {
 		.core_note_type = NT_PRXFPREG,
-		.n = sizeof(struct user_i387_struct) / sizeof(u32),
+		.n = sizeof(struct user32_fxsr_struct) / sizeof(u32),
 		.size = sizeof(u32), .align = sizeof(u32),
 		.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
 	},
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index c0c68c1..6f80b85 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -12,6 +12,7 @@
 #include <asm/mpspec.h>
 #include <asm/apicdef.h>
 
+#ifdef CONFIG_X86_LOCAL_APIC
 unsigned int num_processors;
 unsigned disabled_cpus __cpuinitdata;
 /* Processor that is doing the boot up */
@@ -23,8 +24,9 @@
 
 /* Bitmask of physically existing CPUs */
 physid_mask_t phys_cpu_present_map;
+#endif
 
-#if defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) && defined(CONFIG_SMP)
+#if defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) && defined(CONFIG_X86_SMP)
 /*
  * Copy data used in early init routines from the initial arrays to the
  * per cpu data areas.  These arrays then become expendable and the
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index f2fc8fe..6dff128 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -951,7 +951,7 @@
 static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
 {
 	if (c->x86 == 0x6 && c->x86_model >= 0xf)
-		set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
+		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 }
 
 static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 8f75893..0cb7aad 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -231,7 +231,8 @@
 	wmb();
 
 	/* Send a message to other CPUs */
-	if (cpus_equal(mask, allbutself))
+	if (cpus_equal(mask, allbutself) &&
+	    cpus_equal(cpu_online_map, cpu_callout_map))
 		send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 	else
 		send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6b087ab..3898849 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -86,6 +86,7 @@
 
 #ifdef CONFIG_X86_32
 u8 apicid_2_node[MAX_APICID];
+static int low_mappings;
 #endif
 
 /* State of each CPU */
@@ -326,6 +327,12 @@
 		enable_8259A_irq(0);
 	}
 
+#ifdef CONFIG_X86_32
+	while (low_mappings)
+		cpu_relax();
+	__flush_tlb_all();
+#endif
+
 	/* This must be done before setting cpu_online_map */
 	set_cpu_sibling_map(raw_smp_processor_id());
 	wmb();
@@ -1040,14 +1047,20 @@
 #ifdef CONFIG_X86_32
 	/* init low mem mapping */
 	clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
-			min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
+		min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
 	flush_tlb_all();
-#endif
+	low_mappings = 1;
 
 	err = do_boot_cpu(apicid, cpu);
-	if (err < 0) {
+
+	zap_low_mappings();
+	low_mappings = 0;
+#else
+	err = do_boot_cpu(apicid, cpu);
+#endif
+	if (err) {
 		Dprintk("do_boot_cpu failed %d\n", err);
-		return err;
+		return -EIO;
 	}
 
 	/*
@@ -1259,9 +1272,6 @@
 	setup_ioapic_dest();
 #endif
 	check_nmi_watchdog();
-#ifdef CONFIG_X86_32
-	zap_low_mappings();
-#endif
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 58882f9..f6c05d0 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -2,6 +2,7 @@
    All C exports should go in the respective C files. */
 
 #include <linux/module.h>
+#include <net/checksum.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -29,6 +30,8 @@
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
 
+EXPORT_SYMBOL(csum_partial);
+
 /*
  * Export string functions. We normally rely on gcc builtin for most of these,
  * but gcc sometimes decides not to inline them.
diff --git a/arch/x86/lib/csum-partial_64.c b/arch/x86/lib/csum-partial_64.c
index bc503f5..bf51144 100644
--- a/arch/x86/lib/csum-partial_64.c
+++ b/arch/x86/lib/csum-partial_64.c
@@ -136,8 +136,6 @@
 						(__force u32)sum);
 }
 
-EXPORT_SYMBOL(csum_partial);
-
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index de236e4..ec30d10 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -438,8 +438,6 @@
 {
 	int i;
 
-	save_pg_dir();
-
 	/*
 	 * Zap initial low-memory mappings.
 	 *
@@ -663,16 +661,8 @@
 		test_wp_bit();
 
 	cpa_init();
-
-	/*
-	 * Subtle. SMP is doing it's boot stuff late (because it has to
-	 * fork idle threads) - but it also needs low mappings for the
-	 * protected-mode entry to work. We zap these entries only after
-	 * the WP-bit has been tested.
-	 */
-#ifndef CONFIG_SMP
+	save_pg_dir();
 	zap_low_mappings();
-#endif
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 60adbe2..bcb1a8e 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -555,7 +555,7 @@
 		"%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n",
 			current->comm, current->pid,
 			cattr_name(flags),
-			offset, offset + size);
+			offset, (unsigned long long)(offset + size));
 		return 0;
 	}
 
@@ -576,7 +576,7 @@
 		"%s:%d /dev/mem expected mapping type %s for %Lx-%Lx, got %s\n",
 			current->comm, current->pid,
 			cattr_name(want_flags),
-			addr, addr + size,
+			addr, (unsigned long long)(addr + size),
 			cattr_name(flags));
 	}
 }
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 8af0f0b..10fb308 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -301,15 +301,13 @@
 	prot = pgprot_val(vma->vm_page_prot);
 	if (pat_wc_enabled && write_combine)
 		prot |= _PAGE_CACHE_WC;
-	else if (pat_wc_enabled)
+	else if (pat_wc_enabled || boot_cpu_data.x86 > 3)
 		/*
 		 * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
 		 * To avoid attribute conflicts, request UC MINUS here
 		 * aswell.
 		 */
 		prot |= _PAGE_CACHE_UC_MINUS;
-	else if (boot_cpu_data.x86 > 3)
-		prot |= _PAGE_CACHE_UC;
 
 	vma->vm_page_prot = __pgprot(prot);
 
diff --git a/block/blktrace.c b/block/blktrace.c
index 568588c..b2cbb4e 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -476,7 +476,7 @@
 
 	switch (cmd) {
 	case BLKTRACESETUP:
-		strcpy(b, bdevname(bdev, b));
+		bdevname(bdev, b);
 		ret = blk_trace_setup(q, b, bdev->bd_dev, arg);
 		break;
 	case BLKTRACESTART:
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index c70d0b6..c23177e 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -555,7 +555,7 @@
 	if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
 		return -EFAULT;
 
-	strcpy(b, bdevname(bdev, b));
+	bdevname(bdev, b);
 
 	buts = (struct blk_user_trace_setup) {
 		.act_mask = cbuts.act_mask,
diff --git a/block/genhd.c b/block/genhd.c
index fda9c7a..129ad93 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -653,7 +653,7 @@
 EXPORT_SYMBOL_GPL(genhd_media_change_notify);
 #endif  /*  0  */
 
-dev_t blk_lookup_devt(const char *name)
+dev_t blk_lookup_devt(const char *name, int part)
 {
 	struct device *dev;
 	dev_t devt = MKDEV(0, 0);
@@ -661,7 +661,11 @@
 	mutex_lock(&block_class_lock);
 	list_for_each_entry(dev, &block_class.devices, node) {
 		if (strcmp(dev->bus_id, name) == 0) {
-			devt = dev->devt;
+			struct gendisk *disk = dev_to_disk(dev);
+
+			if (part < disk->minors)
+				devt = MKDEV(MAJOR(dev->devt),
+					     MINOR(dev->devt) + part);
 			break;
 		}
 	}
@@ -669,7 +673,6 @@
 
 	return devt;
 }
-
 EXPORT_SYMBOL(blk_lookup_devt);
 
 struct gendisk *alloc_disk(int minors)
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 0ef00e8..e085af0 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -140,7 +140,6 @@
 
 	pr_debug("device class '%s': registering\n", cls->name);
 
-	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->devices);
 	INIT_LIST_HEAD(&cls->interfaces);
 	kset_init(&cls->class_dirs);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 8ce6de5..937e825 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -53,11 +53,13 @@
 {
         return blocking_notifier_chain_register(&memory_chain, nb);
 }
+EXPORT_SYMBOL(register_memory_notifier);
 
 void unregister_memory_notifier(struct notifier_block *nb)
 {
         blocking_notifier_chain_unregister(&memory_chain, nb);
 }
+EXPORT_SYMBOL(unregister_memory_notifier);
 
 /*
  * register_memory - Setup a sysfs device for a memory block
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2001b0e..55c1653 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -916,7 +916,7 @@
 {
 	struct slgt_info *info = tty->driver_data;
 	unsigned long flags;
-	int ret;
+	int ret = 0;
 
 	if (sanity_check(info, tty->name, "put_char"))
 		return 0;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 087eee0..ee0ea91 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2369,8 +2369,8 @@
 
 	/* complete a check operation */
 	if (test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) {
-	    clear_bit(STRIPE_OP_CHECK, &sh->ops.ack);
-	    clear_bit(STRIPE_OP_CHECK, &sh->ops.pending);
+		clear_bit(STRIPE_OP_CHECK, &sh->ops.ack);
+		clear_bit(STRIPE_OP_CHECK, &sh->ops.pending);
 		if (s->failed == 0) {
 			if (sh->ops.zero_sum_result == 0)
 				/* parity is correct (on disc,
@@ -2400,16 +2400,6 @@
 			canceled_check = 1; /* STRIPE_INSYNC is not set */
 	}
 
-	/* check if we can clear a parity disk reconstruct */
-	if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
-		test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
-
-		clear_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending);
-		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
-		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
-		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
-	}
-
 	/* start a new check operation if there are no failures, the stripe is
 	 * not insync, and a repair is not in flight
 	 */
@@ -2424,6 +2414,17 @@
 		}
 	}
 
+	/* check if we can clear a parity disk reconstruct */
+	if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
+	    test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
+
+		clear_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending);
+		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
+		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
+		clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
+	}
+
+
 	/* Wait for check parity and compute block operations to complete
 	 * before write-back.  If a failure occurred while the check operation
 	 * was in flight we need to cycle this stripe through handle_stripe
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index ddf57e1..7a7803b 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -89,8 +89,7 @@
 
 config VIDEO_MEDIA
 	tristate
-	default DVB_CORE || VIDEO_DEV
-	depends on DVB_CORE || VIDEO_DEV
+	default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
 
 comment "Multimedia drivers"
 
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 5be85ff..d620654 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -1,6 +1,6 @@
 config MEDIA_ATTACH
 	bool "Load and attach frontend and tuner driver modules as needed"
-	depends on DVB_CORE
+	depends on VIDEO_MEDIA
 	depends on MODULES
 	help
 	  Remove the static dependency of DVB card drivers on all
@@ -19,10 +19,10 @@
 
 config MEDIA_TUNER
 	tristate
-	default DVB_CORE || VIDEO_DEV
-	depends on DVB_CORE || VIDEO_DEV
-	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
-	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
+	default VIDEO_MEDIA && I2C
+	depends on VIDEO_MEDIA && I2C
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
 	select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
 	select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
@@ -46,7 +46,7 @@
 
 config MEDIA_TUNER_SIMPLE
 	tristate "Simple tuner support"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	select MEDIA_TUNER_TDA9887
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
@@ -54,7 +54,7 @@
 
 config MEDIA_TUNER_TDA8290
 	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	select MEDIA_TUNER_TDA827X
 	select MEDIA_TUNER_TDA18271
 	default m if MEDIA_TUNER_CUSTOMIZE
@@ -63,21 +63,21 @@
 
 config MEDIA_TUNER_TDA827X
 	tristate "Philips TDA827X silicon tuner"
-	depends on DVB_CORE && I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA18271
 	tristate "NXP TDA18271 silicon tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA9887
 	tristate "TDA 9885/6/7 analog IF demodulator"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for Philips TDA9885/6/7
@@ -85,67 +85,79 @@
 
 config MEDIA_TUNER_TEA5761
 	tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
-	depends on I2C && EXPERIMENTAL
+	depends on VIDEO_MEDIA && I2C
+	depends on EXPERIMENTAL
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for the Philips TEA5761 radio tuner.
 
 config MEDIA_TUNER_TEA5767
 	tristate "TEA 5767 radio tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for the Philips TEA5767 radio tuner.
 
 config MEDIA_TUNER_MT20XX
 	tristate "Microtune 2032 / 2050 tuners"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config MEDIA_TUNER_MT2060
 	tristate "Microtune MT2060 silicon IF tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A driver for the silicon IF tuner MT2060 from Microtune.
 
 config MEDIA_TUNER_MT2266
 	tristate "Microtune MT2266 silicon tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A driver for the silicon baseband tuner MT2266 from Microtune.
 
 config MEDIA_TUNER_MT2131
 	tristate "Microtune MT2131 silicon tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A driver for the silicon baseband tuner MT2131 from Microtune.
 
 config MEDIA_TUNER_QT1010
 	tristate "Quantek QT1010 silicon tuner"
-	depends on DVB_CORE && I2C
+	depends on VIDEO_MEDIA && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A driver for the silicon tuner QT1010 from Quantek.
 
 config MEDIA_TUNER_XC2028
 	tristate "XCeive xc2028/xc3028 tuners"
-	depends on I2C && FW_LOADER
+	depends on VIDEO_MEDIA && I2C
+	depends on HOTPLUG
+	select FW_LOADER
 	default m if MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for the xc2028/xc3028 tuners.
 
 config MEDIA_TUNER_XC5000
 	tristate "Xceive XC5000 silicon tuner"
-	depends on I2C
+	depends on VIDEO_MEDIA && I2C
+	depends on HOTPLUG
+	select FW_LOADER
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A driver for the silicon tuner XC5000 from Xceive.
 	  This device is only used inside a SiP called togther with a
 	  demodulator for now.
 
+config MEDIA_TUNER_MXL5005S
+	tristate "MaxLinear MSL5005S silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon tuner MXL5005S from MaxLinear.
+
 endif # MEDIA_TUNER_CUSTOMIZE
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 236d993..55f7e67 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
new file mode 100644
index 0000000..5d05b53
--- /dev/null
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -0,0 +1,4110 @@
+/*
+    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+    Copyright (C) 2008 MaxLinear
+    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+      Functions:
+	mxl5005s_reset()
+	mxl5005s_writereg()
+	mxl5005s_writeregs()
+	mxl5005s_init()
+	mxl5005s_reconfigure()
+	mxl5005s_AssignTunerMode()
+	mxl5005s_set_params()
+	mxl5005s_get_frequency()
+	mxl5005s_get_bandwidth()
+	mxl5005s_release()
+	mxl5005s_attach()
+
+    Copyright (C) 2008 Realtek
+    Copyright (C) 2008 Jan Hoogenraad
+      Functions:
+	mxl5005s_SetRfFreqHz()
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/*
+    History of this driver (Steven Toth):
+      I was given a public release of a linux driver that included
+      support for the MaxLinear MXL5005S silicon tuner. Analysis of
+      the tuner driver showed clearly three things.
+
+      1. The tuner driver didn't support the LinuxTV tuner API
+	 so the code Realtek added had to be removed.
+
+      2. A significant amount of the driver is reference driver code
+	 from MaxLinear, I felt it was important to identify and
+	 preserve this.
+
+      3. New code has to be added to interface correctly with the
+	 LinuxTV API, as a regular kernel module.
+
+      Other than the reference driver enum's, I've clearly marked
+      sections of the code and retained the copyright of the
+      respective owners.
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "mxl5005s.h"
+
+static int debug;
+
+#define dprintk(level, arg...) do {    \
+	if (level <= debug)            \
+		printk(arg);    \
+	} while (0)
+
+#define TUNER_REGS_NUM          104
+#define INITCTRL_NUM            40
+
+#ifdef _MXL_PRODUCTION
+#define CHCTRL_NUM              39
+#else
+#define CHCTRL_NUM              36
+#endif
+
+#define MXLCTRL_NUM             189
+#define MASTER_CONTROL_ADDR     9
+
+/* Enumeration of Master Control Register State */
+enum master_control_state {
+	MC_LOAD_START = 1,
+	MC_POWER_DOWN,
+	MC_SYNTH_RESET,
+	MC_SEQ_OFF
+};
+
+/* Enumeration of MXL5005 Tuner Modulation Type */
+enum {
+	MXL_DEFAULT_MODULATION = 0,
+	MXL_DVBT,
+	MXL_ATSC,
+	MXL_QAM,
+	MXL_ANALOG_CABLE,
+	MXL_ANALOG_OTA
+} tuner_modu_type;
+
+/* MXL5005 Tuner Register Struct */
+struct TunerReg {
+	u16 Reg_Num;	/* Tuner Register Address */
+	u16 Reg_Val;	/* Current sw programmed value waiting to be writen */
+};
+
+enum {
+	/* Initialization Control Names */
+	DN_IQTN_AMP_CUT = 1,       /* 1 */
+	BB_MODE,                   /* 2 */
+	BB_BUF,                    /* 3 */
+	BB_BUF_OA,                 /* 4 */
+	BB_ALPF_BANDSELECT,        /* 5 */
+	BB_IQSWAP,                 /* 6 */
+	BB_DLPF_BANDSEL,           /* 7 */
+	RFSYN_CHP_GAIN,            /* 8 */
+	RFSYN_EN_CHP_HIGAIN,       /* 9 */
+	AGC_IF,                    /* 10 */
+	AGC_RF,                    /* 11 */
+	IF_DIVVAL,                 /* 12 */
+	IF_VCO_BIAS,               /* 13 */
+	CHCAL_INT_MOD_IF,          /* 14 */
+	CHCAL_FRAC_MOD_IF,         /* 15 */
+	DRV_RES_SEL,               /* 16 */
+	I_DRIVER,                  /* 17 */
+	EN_AAF,                    /* 18 */
+	EN_3P,                     /* 19 */
+	EN_AUX_3P,                 /* 20 */
+	SEL_AAF_BAND,              /* 21 */
+	SEQ_ENCLK16_CLK_OUT,       /* 22 */
+	SEQ_SEL4_16B,              /* 23 */
+	XTAL_CAPSELECT,            /* 24 */
+	IF_SEL_DBL,                /* 25 */
+	RFSYN_R_DIV,               /* 26 */
+	SEQ_EXTSYNTHCALIF,         /* 27 */
+	SEQ_EXTDCCAL,              /* 28 */
+	AGC_EN_RSSI,               /* 29 */
+	RFA_ENCLKRFAGC,            /* 30 */
+	RFA_RSSI_REFH,             /* 31 */
+	RFA_RSSI_REF,              /* 32 */
+	RFA_RSSI_REFL,             /* 33 */
+	RFA_FLR,                   /* 34 */
+	RFA_CEIL,                  /* 35 */
+	SEQ_EXTIQFSMPULSE,         /* 36 */
+	OVERRIDE_1,                /* 37 */
+	BB_INITSTATE_DLPF_TUNE,    /* 38 */
+	TG_R_DIV,                  /* 39 */
+	EN_CHP_LIN_B,              /* 40 */
+
+	/* Channel Change Control Names */
+	DN_POLY = 51,              /* 51 */
+	DN_RFGAIN,                 /* 52 */
+	DN_CAP_RFLPF,              /* 53 */
+	DN_EN_VHFUHFBAR,           /* 54 */
+	DN_GAIN_ADJUST,            /* 55 */
+	DN_IQTNBUF_AMP,            /* 56 */
+	DN_IQTNGNBFBIAS_BST,       /* 57 */
+	RFSYN_EN_OUTMUX,           /* 58 */
+	RFSYN_SEL_VCO_OUT,         /* 59 */
+	RFSYN_SEL_VCO_HI,          /* 60 */
+	RFSYN_SEL_DIVM,            /* 61 */
+	RFSYN_RF_DIV_BIAS,         /* 62 */
+	DN_SEL_FREQ,               /* 63 */
+	RFSYN_VCO_BIAS,            /* 64 */
+	CHCAL_INT_MOD_RF,          /* 65 */
+	CHCAL_FRAC_MOD_RF,         /* 66 */
+	RFSYN_LPF_R,               /* 67 */
+	CHCAL_EN_INT_RF,           /* 68 */
+	TG_LO_DIVVAL,              /* 69 */
+	TG_LO_SELVAL,              /* 70 */
+	TG_DIV_VAL,                /* 71 */
+	TG_VCO_BIAS,               /* 72 */
+	SEQ_EXTPOWERUP,            /* 73 */
+	OVERRIDE_2,                /* 74 */
+	OVERRIDE_3,                /* 75 */
+	OVERRIDE_4,                /* 76 */
+	SEQ_FSM_PULSE,             /* 77 */
+	GPIO_4B,                   /* 78 */
+	GPIO_3B,                   /* 79 */
+	GPIO_4,                    /* 80 */
+	GPIO_3,                    /* 81 */
+	GPIO_1B,                   /* 82 */
+	DAC_A_ENABLE,              /* 83 */
+	DAC_B_ENABLE,              /* 84 */
+	DAC_DIN_A,                 /* 85 */
+	DAC_DIN_B,                 /* 86 */
+#ifdef _MXL_PRODUCTION
+	RFSYN_EN_DIV,              /* 87 */
+	RFSYN_DIVM,                /* 88 */
+	DN_BYPASS_AGC_I2C          /* 89 */
+#endif
+} MXL5005_ControlName;
+
+/*
+ * The following context is source code provided by MaxLinear.
+ * MaxLinear source code - Common_MXL.h (?)
+ */
+
+/* Constants */
+#define MXL5005S_REG_WRITING_TABLE_LEN_MAX	104
+#define MXL5005S_LATCH_BYTE			0xfe
+
+/* Register address, MSB, and LSB */
+#define MXL5005S_BB_IQSWAP_ADDR			59
+#define MXL5005S_BB_IQSWAP_MSB			0
+#define MXL5005S_BB_IQSWAP_LSB			0
+
+#define MXL5005S_BB_DLPF_BANDSEL_ADDR		53
+#define MXL5005S_BB_DLPF_BANDSEL_MSB		4
+#define MXL5005S_BB_DLPF_BANDSEL_LSB		3
+
+/* Standard modes */
+enum {
+	MXL5005S_STANDARD_DVBT,
+	MXL5005S_STANDARD_ATSC,
+};
+#define MXL5005S_STANDARD_MODE_NUM		2
+
+/* Bandwidth modes */
+enum {
+	MXL5005S_BANDWIDTH_6MHZ = 6000000,
+	MXL5005S_BANDWIDTH_7MHZ = 7000000,
+	MXL5005S_BANDWIDTH_8MHZ = 8000000,
+};
+#define MXL5005S_BANDWIDTH_MODE_NUM		3
+
+/* MXL5005 Tuner Control Struct */
+struct TunerControl {
+	u16 Ctrl_Num;	/* Control Number */
+	u16 size;	/* Number of bits to represent Value */
+	u16 addr[25];	/* Array of Tuner Register Address for each bit pos */
+	u16 bit[25];	/* Array of bit pos in Reg Addr for each bit pos */
+	u16 val[25];	/* Binary representation of Value */
+};
+
+/* MXL5005 Tuner Struct */
+struct mxl5005s_state {
+	u8	Mode;		/* 0: Analog Mode ; 1: Digital Mode */
+	u8	IF_Mode;	/* for Analog Mode, 0: zero IF; 1: low IF */
+	u32	Chan_Bandwidth;	/* filter  channel bandwidth (6, 7, 8) */
+	u32	IF_OUT;		/* Desired IF Out Frequency */
+	u16	IF_OUT_LOAD;	/* IF Out Load Resistor (200/300 Ohms) */
+	u32	RF_IN;		/* RF Input Frequency */
+	u32	Fxtal;		/* XTAL Frequency */
+	u8	AGC_Mode;	/* AGC Mode 0: Dual AGC; 1: Single AGC */
+	u16	TOP;		/* Value: take over point */
+	u8	CLOCK_OUT;	/* 0: turn off clk out; 1: turn on clock out */
+	u8	DIV_OUT;	/* 4MHz or 16MHz */
+	u8	CAPSELECT;	/* 0: disable On-Chip pulling cap; 1: enable */
+	u8	EN_RSSI;	/* 0: disable RSSI; 1: enable RSSI */
+
+	/* Modulation Type; */
+	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+	u8	Mod_Type;
+
+	/* Tracking Filter Type */
+	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+	u8	TF_Type;
+
+	/* Calculated Settings */
+	u32	RF_LO;		/* Synth RF LO Frequency */
+	u32	IF_LO;		/* Synth IF LO Frequency */
+	u32	TG_LO;		/* Synth TG_LO Frequency */
+
+	/* Pointers to ControlName Arrays */
+	u16	Init_Ctrl_Num;		/* Number of INIT Control Names */
+	struct TunerControl
+		Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */
+
+	u16	CH_Ctrl_Num;		/* Number of CH Control Names */
+	struct TunerControl
+		CH_Ctrl[CHCTRL_NUM];	/* CH Control Name Array Pointer */
+
+	u16	MXL_Ctrl_Num;		/* Number of MXL Control Names */
+	struct TunerControl
+		MXL_Ctrl[MXLCTRL_NUM];	/* MXL Control Name Array Pointer */
+
+	/* Pointer to Tuner Register Array */
+	u16	TunerRegs_Num;		/* Number of Tuner Registers */
+	struct TunerReg
+		TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */
+
+	/* Linux driver framework specific */
+	struct mxl5005s_config *config;
+	struct dvb_frontend *frontend;
+	struct i2c_adapter *i2c;
+
+	/* Cache values */
+	u32 current_mode;
+
+};
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state);
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value);
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value);
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+	u8 bitVal);
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static u32 MXL_Ceiling(u32 value, u32 resolution);
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal);
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+	u32 value, u16 controlGroup);
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static u32 MXL_GetXtalInt(u32 Xtal_Freq);
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+	u8 *datatable, u8 len);
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe);
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth);
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth);
+
+/* ----------------------------------------------------------------
+ * Begin: Custom code salvaged from the Realtek driver.
+ * Copyright (C) 2008 Realtek
+ * Copyright (C) 2008 Jan Hoogenraad
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * Released by Realtek under GPLv2.
+ * Thanks to Realtek for a lot of support we received !
+ *
+ *  Revision: 080314 - original version
+ */
+
+static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	int TableLen;
+
+	u32 IfDivval = 0;
+	unsigned char MasterControlByte;
+
+	dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz);
+
+	/* Set MxL5005S tuner RF frequency according to example code. */
+
+	/* Tuner RF frequency setting stage 0 */
+	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+	AddrTable[0] = MASTER_CONTROL_ADDR;
+	ByteTable[0] |= state->config->AgcMasterByte;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+	/* Tuner RF frequency setting stage 1 */
+	MXL_TuneRF(fe, RfFreqHz);
+
+	MXL_ControlRead(fe, IF_DIVVAL, &IfDivval);
+
+	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0);
+	MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1);
+	MXL_ControlWrite(fe, IF_DIVVAL, 8);
+	MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen);
+
+	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+	ByteTable[TableLen] = MasterControlByte |
+		state->config->AgcMasterByte;
+	TableLen += 1;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	/* Wait 30 ms. */
+	msleep(150);
+
+	/* Tuner RF frequency setting stage 2 */
+	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1);
+	MXL_ControlWrite(fe, IF_DIVVAL, IfDivval);
+	MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen);
+
+	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+	ByteTable[TableLen] = MasterControlByte |
+		state->config->AgcMasterByte ;
+	TableLen += 1;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	msleep(100);
+
+	return 0;
+}
+/* End: Custom code taken from the Realtek driver */
+
+/* ----------------------------------------------------------------
+ * Begin: Reference driver code found in the Realtek driver.
+ * Copyright (C) 2008 MaxLinear
+ */
+static u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	state->TunerRegs_Num = TUNER_REGS_NUM ;
+
+	state->TunerRegs[0].Reg_Num = 9 ;
+	state->TunerRegs[0].Reg_Val = 0x40 ;
+
+	state->TunerRegs[1].Reg_Num = 11 ;
+	state->TunerRegs[1].Reg_Val = 0x19 ;
+
+	state->TunerRegs[2].Reg_Num = 12 ;
+	state->TunerRegs[2].Reg_Val = 0x60 ;
+
+	state->TunerRegs[3].Reg_Num = 13 ;
+	state->TunerRegs[3].Reg_Val = 0x00 ;
+
+	state->TunerRegs[4].Reg_Num = 14 ;
+	state->TunerRegs[4].Reg_Val = 0x00 ;
+
+	state->TunerRegs[5].Reg_Num = 15 ;
+	state->TunerRegs[5].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[6].Reg_Num = 16 ;
+	state->TunerRegs[6].Reg_Val = 0x00 ;
+
+	state->TunerRegs[7].Reg_Num = 17 ;
+	state->TunerRegs[7].Reg_Val = 0x00 ;
+
+	state->TunerRegs[8].Reg_Num = 18 ;
+	state->TunerRegs[8].Reg_Val = 0x00 ;
+
+	state->TunerRegs[9].Reg_Num = 19 ;
+	state->TunerRegs[9].Reg_Val = 0x34 ;
+
+	state->TunerRegs[10].Reg_Num = 21 ;
+	state->TunerRegs[10].Reg_Val = 0x00 ;
+
+	state->TunerRegs[11].Reg_Num = 22 ;
+	state->TunerRegs[11].Reg_Val = 0x6B ;
+
+	state->TunerRegs[12].Reg_Num = 23 ;
+	state->TunerRegs[12].Reg_Val = 0x35 ;
+
+	state->TunerRegs[13].Reg_Num = 24 ;
+	state->TunerRegs[13].Reg_Val = 0x70 ;
+
+	state->TunerRegs[14].Reg_Num = 25 ;
+	state->TunerRegs[14].Reg_Val = 0x3E ;
+
+	state->TunerRegs[15].Reg_Num = 26 ;
+	state->TunerRegs[15].Reg_Val = 0x82 ;
+
+	state->TunerRegs[16].Reg_Num = 31 ;
+	state->TunerRegs[16].Reg_Val = 0x00 ;
+
+	state->TunerRegs[17].Reg_Num = 32 ;
+	state->TunerRegs[17].Reg_Val = 0x40 ;
+
+	state->TunerRegs[18].Reg_Num = 33 ;
+	state->TunerRegs[18].Reg_Val = 0x53 ;
+
+	state->TunerRegs[19].Reg_Num = 34 ;
+	state->TunerRegs[19].Reg_Val = 0x81 ;
+
+	state->TunerRegs[20].Reg_Num = 35 ;
+	state->TunerRegs[20].Reg_Val = 0xC9 ;
+
+	state->TunerRegs[21].Reg_Num = 36 ;
+	state->TunerRegs[21].Reg_Val = 0x01 ;
+
+	state->TunerRegs[22].Reg_Num = 37 ;
+	state->TunerRegs[22].Reg_Val = 0x00 ;
+
+	state->TunerRegs[23].Reg_Num = 41 ;
+	state->TunerRegs[23].Reg_Val = 0x00 ;
+
+	state->TunerRegs[24].Reg_Num = 42 ;
+	state->TunerRegs[24].Reg_Val = 0xF8 ;
+
+	state->TunerRegs[25].Reg_Num = 43 ;
+	state->TunerRegs[25].Reg_Val = 0x43 ;
+
+	state->TunerRegs[26].Reg_Num = 44 ;
+	state->TunerRegs[26].Reg_Val = 0x20 ;
+
+	state->TunerRegs[27].Reg_Num = 45 ;
+	state->TunerRegs[27].Reg_Val = 0x80 ;
+
+	state->TunerRegs[28].Reg_Num = 46 ;
+	state->TunerRegs[28].Reg_Val = 0x88 ;
+
+	state->TunerRegs[29].Reg_Num = 47 ;
+	state->TunerRegs[29].Reg_Val = 0x86 ;
+
+	state->TunerRegs[30].Reg_Num = 48 ;
+	state->TunerRegs[30].Reg_Val = 0x00 ;
+
+	state->TunerRegs[31].Reg_Num = 49 ;
+	state->TunerRegs[31].Reg_Val = 0x00 ;
+
+	state->TunerRegs[32].Reg_Num = 53 ;
+	state->TunerRegs[32].Reg_Val = 0x94 ;
+
+	state->TunerRegs[33].Reg_Num = 54 ;
+	state->TunerRegs[33].Reg_Val = 0xFA ;
+
+	state->TunerRegs[34].Reg_Num = 55 ;
+	state->TunerRegs[34].Reg_Val = 0x92 ;
+
+	state->TunerRegs[35].Reg_Num = 56 ;
+	state->TunerRegs[35].Reg_Val = 0x80 ;
+
+	state->TunerRegs[36].Reg_Num = 57 ;
+	state->TunerRegs[36].Reg_Val = 0x41 ;
+
+	state->TunerRegs[37].Reg_Num = 58 ;
+	state->TunerRegs[37].Reg_Val = 0xDB ;
+
+	state->TunerRegs[38].Reg_Num = 59 ;
+	state->TunerRegs[38].Reg_Val = 0x00 ;
+
+	state->TunerRegs[39].Reg_Num = 60 ;
+	state->TunerRegs[39].Reg_Val = 0x00 ;
+
+	state->TunerRegs[40].Reg_Num = 61 ;
+	state->TunerRegs[40].Reg_Val = 0x00 ;
+
+	state->TunerRegs[41].Reg_Num = 62 ;
+	state->TunerRegs[41].Reg_Val = 0x00 ;
+
+	state->TunerRegs[42].Reg_Num = 65 ;
+	state->TunerRegs[42].Reg_Val = 0xF8 ;
+
+	state->TunerRegs[43].Reg_Num = 66 ;
+	state->TunerRegs[43].Reg_Val = 0xE4 ;
+
+	state->TunerRegs[44].Reg_Num = 67 ;
+	state->TunerRegs[44].Reg_Val = 0x90 ;
+
+	state->TunerRegs[45].Reg_Num = 68 ;
+	state->TunerRegs[45].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[46].Reg_Num = 69 ;
+	state->TunerRegs[46].Reg_Val = 0x01 ;
+
+	state->TunerRegs[47].Reg_Num = 70 ;
+	state->TunerRegs[47].Reg_Val = 0x50 ;
+
+	state->TunerRegs[48].Reg_Num = 71 ;
+	state->TunerRegs[48].Reg_Val = 0x06 ;
+
+	state->TunerRegs[49].Reg_Num = 72 ;
+	state->TunerRegs[49].Reg_Val = 0x00 ;
+
+	state->TunerRegs[50].Reg_Num = 73 ;
+	state->TunerRegs[50].Reg_Val = 0x20 ;
+
+	state->TunerRegs[51].Reg_Num = 76 ;
+	state->TunerRegs[51].Reg_Val = 0xBB ;
+
+	state->TunerRegs[52].Reg_Num = 77 ;
+	state->TunerRegs[52].Reg_Val = 0x13 ;
+
+	state->TunerRegs[53].Reg_Num = 81 ;
+	state->TunerRegs[53].Reg_Val = 0x04 ;
+
+	state->TunerRegs[54].Reg_Num = 82 ;
+	state->TunerRegs[54].Reg_Val = 0x75 ;
+
+	state->TunerRegs[55].Reg_Num = 83 ;
+	state->TunerRegs[55].Reg_Val = 0x00 ;
+
+	state->TunerRegs[56].Reg_Num = 84 ;
+	state->TunerRegs[56].Reg_Val = 0x00 ;
+
+	state->TunerRegs[57].Reg_Num = 85 ;
+	state->TunerRegs[57].Reg_Val = 0x00 ;
+
+	state->TunerRegs[58].Reg_Num = 91 ;
+	state->TunerRegs[58].Reg_Val = 0x70 ;
+
+	state->TunerRegs[59].Reg_Num = 92 ;
+	state->TunerRegs[59].Reg_Val = 0x00 ;
+
+	state->TunerRegs[60].Reg_Num = 93 ;
+	state->TunerRegs[60].Reg_Val = 0x00 ;
+
+	state->TunerRegs[61].Reg_Num = 94 ;
+	state->TunerRegs[61].Reg_Val = 0x00 ;
+
+	state->TunerRegs[62].Reg_Num = 95 ;
+	state->TunerRegs[62].Reg_Val = 0x0C ;
+
+	state->TunerRegs[63].Reg_Num = 96 ;
+	state->TunerRegs[63].Reg_Val = 0x00 ;
+
+	state->TunerRegs[64].Reg_Num = 97 ;
+	state->TunerRegs[64].Reg_Val = 0x00 ;
+
+	state->TunerRegs[65].Reg_Num = 98 ;
+	state->TunerRegs[65].Reg_Val = 0xE2 ;
+
+	state->TunerRegs[66].Reg_Num = 99 ;
+	state->TunerRegs[66].Reg_Val = 0x00 ;
+
+	state->TunerRegs[67].Reg_Num = 100 ;
+	state->TunerRegs[67].Reg_Val = 0x00 ;
+
+	state->TunerRegs[68].Reg_Num = 101 ;
+	state->TunerRegs[68].Reg_Val = 0x12 ;
+
+	state->TunerRegs[69].Reg_Num = 102 ;
+	state->TunerRegs[69].Reg_Val = 0x80 ;
+
+	state->TunerRegs[70].Reg_Num = 103 ;
+	state->TunerRegs[70].Reg_Val = 0x32 ;
+
+	state->TunerRegs[71].Reg_Num = 104 ;
+	state->TunerRegs[71].Reg_Val = 0xB4 ;
+
+	state->TunerRegs[72].Reg_Num = 105 ;
+	state->TunerRegs[72].Reg_Val = 0x60 ;
+
+	state->TunerRegs[73].Reg_Num = 106 ;
+	state->TunerRegs[73].Reg_Val = 0x83 ;
+
+	state->TunerRegs[74].Reg_Num = 107 ;
+	state->TunerRegs[74].Reg_Val = 0x84 ;
+
+	state->TunerRegs[75].Reg_Num = 108 ;
+	state->TunerRegs[75].Reg_Val = 0x9C ;
+
+	state->TunerRegs[76].Reg_Num = 109 ;
+	state->TunerRegs[76].Reg_Val = 0x02 ;
+
+	state->TunerRegs[77].Reg_Num = 110 ;
+	state->TunerRegs[77].Reg_Val = 0x81 ;
+
+	state->TunerRegs[78].Reg_Num = 111 ;
+	state->TunerRegs[78].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[79].Reg_Num = 112 ;
+	state->TunerRegs[79].Reg_Val = 0x10 ;
+
+	state->TunerRegs[80].Reg_Num = 131 ;
+	state->TunerRegs[80].Reg_Val = 0x8A ;
+
+	state->TunerRegs[81].Reg_Num = 132 ;
+	state->TunerRegs[81].Reg_Val = 0x10 ;
+
+	state->TunerRegs[82].Reg_Num = 133 ;
+	state->TunerRegs[82].Reg_Val = 0x24 ;
+
+	state->TunerRegs[83].Reg_Num = 134 ;
+	state->TunerRegs[83].Reg_Val = 0x00 ;
+
+	state->TunerRegs[84].Reg_Num = 135 ;
+	state->TunerRegs[84].Reg_Val = 0x00 ;
+
+	state->TunerRegs[85].Reg_Num = 136 ;
+	state->TunerRegs[85].Reg_Val = 0x7E ;
+
+	state->TunerRegs[86].Reg_Num = 137 ;
+	state->TunerRegs[86].Reg_Val = 0x40 ;
+
+	state->TunerRegs[87].Reg_Num = 138 ;
+	state->TunerRegs[87].Reg_Val = 0x38 ;
+
+	state->TunerRegs[88].Reg_Num = 146 ;
+	state->TunerRegs[88].Reg_Val = 0xF6 ;
+
+	state->TunerRegs[89].Reg_Num = 147 ;
+	state->TunerRegs[89].Reg_Val = 0x1A ;
+
+	state->TunerRegs[90].Reg_Num = 148 ;
+	state->TunerRegs[90].Reg_Val = 0x62 ;
+
+	state->TunerRegs[91].Reg_Num = 149 ;
+	state->TunerRegs[91].Reg_Val = 0x33 ;
+
+	state->TunerRegs[92].Reg_Num = 150 ;
+	state->TunerRegs[92].Reg_Val = 0x80 ;
+
+	state->TunerRegs[93].Reg_Num = 156 ;
+	state->TunerRegs[93].Reg_Val = 0x56 ;
+
+	state->TunerRegs[94].Reg_Num = 157 ;
+	state->TunerRegs[94].Reg_Val = 0x17 ;
+
+	state->TunerRegs[95].Reg_Num = 158 ;
+	state->TunerRegs[95].Reg_Val = 0xA9 ;
+
+	state->TunerRegs[96].Reg_Num = 159 ;
+	state->TunerRegs[96].Reg_Val = 0x00 ;
+
+	state->TunerRegs[97].Reg_Num = 160 ;
+	state->TunerRegs[97].Reg_Val = 0x00 ;
+
+	state->TunerRegs[98].Reg_Num = 161 ;
+	state->TunerRegs[98].Reg_Val = 0x00 ;
+
+	state->TunerRegs[99].Reg_Num = 162 ;
+	state->TunerRegs[99].Reg_Val = 0x40 ;
+
+	state->TunerRegs[100].Reg_Num = 166 ;
+	state->TunerRegs[100].Reg_Val = 0xAE ;
+
+	state->TunerRegs[101].Reg_Num = 167 ;
+	state->TunerRegs[101].Reg_Val = 0x1B ;
+
+	state->TunerRegs[102].Reg_Num = 168 ;
+	state->TunerRegs[102].Reg_Val = 0xF2 ;
+
+	state->TunerRegs[103].Reg_Num = 195 ;
+	state->TunerRegs[103].Reg_Val = 0x00 ;
+
+	return 0 ;
+}
+
+static u16 MXL5005_ControlInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	state->Init_Ctrl_Num = INITCTRL_NUM;
+
+	state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ;
+	state->Init_Ctrl[0].size = 1 ;
+	state->Init_Ctrl[0].addr[0] = 73;
+	state->Init_Ctrl[0].bit[0] = 7;
+	state->Init_Ctrl[0].val[0] = 0;
+
+	state->Init_Ctrl[1].Ctrl_Num = BB_MODE ;
+	state->Init_Ctrl[1].size = 1 ;
+	state->Init_Ctrl[1].addr[0] = 53;
+	state->Init_Ctrl[1].bit[0] = 2;
+	state->Init_Ctrl[1].val[0] = 1;
+
+	state->Init_Ctrl[2].Ctrl_Num = BB_BUF ;
+	state->Init_Ctrl[2].size = 2 ;
+	state->Init_Ctrl[2].addr[0] = 53;
+	state->Init_Ctrl[2].bit[0] = 1;
+	state->Init_Ctrl[2].val[0] = 0;
+	state->Init_Ctrl[2].addr[1] = 57;
+	state->Init_Ctrl[2].bit[1] = 0;
+	state->Init_Ctrl[2].val[1] = 1;
+
+	state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ;
+	state->Init_Ctrl[3].size = 1 ;
+	state->Init_Ctrl[3].addr[0] = 53;
+	state->Init_Ctrl[3].bit[0] = 0;
+	state->Init_Ctrl[3].val[0] = 0;
+
+	state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ;
+	state->Init_Ctrl[4].size = 3 ;
+	state->Init_Ctrl[4].addr[0] = 53;
+	state->Init_Ctrl[4].bit[0] = 5;
+	state->Init_Ctrl[4].val[0] = 0;
+	state->Init_Ctrl[4].addr[1] = 53;
+	state->Init_Ctrl[4].bit[1] = 6;
+	state->Init_Ctrl[4].val[1] = 0;
+	state->Init_Ctrl[4].addr[2] = 53;
+	state->Init_Ctrl[4].bit[2] = 7;
+	state->Init_Ctrl[4].val[2] = 1;
+
+	state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ;
+	state->Init_Ctrl[5].size = 1 ;
+	state->Init_Ctrl[5].addr[0] = 59;
+	state->Init_Ctrl[5].bit[0] = 0;
+	state->Init_Ctrl[5].val[0] = 0;
+
+	state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ;
+	state->Init_Ctrl[6].size = 2 ;
+	state->Init_Ctrl[6].addr[0] = 53;
+	state->Init_Ctrl[6].bit[0] = 3;
+	state->Init_Ctrl[6].val[0] = 0;
+	state->Init_Ctrl[6].addr[1] = 53;
+	state->Init_Ctrl[6].bit[1] = 4;
+	state->Init_Ctrl[6].val[1] = 1;
+
+	state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ;
+	state->Init_Ctrl[7].size = 4 ;
+	state->Init_Ctrl[7].addr[0] = 22;
+	state->Init_Ctrl[7].bit[0] = 4;
+	state->Init_Ctrl[7].val[0] = 0;
+	state->Init_Ctrl[7].addr[1] = 22;
+	state->Init_Ctrl[7].bit[1] = 5;
+	state->Init_Ctrl[7].val[1] = 1;
+	state->Init_Ctrl[7].addr[2] = 22;
+	state->Init_Ctrl[7].bit[2] = 6;
+	state->Init_Ctrl[7].val[2] = 1;
+	state->Init_Ctrl[7].addr[3] = 22;
+	state->Init_Ctrl[7].bit[3] = 7;
+	state->Init_Ctrl[7].val[3] = 0;
+
+	state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ;
+	state->Init_Ctrl[8].size = 1 ;
+	state->Init_Ctrl[8].addr[0] = 22;
+	state->Init_Ctrl[8].bit[0] = 2;
+	state->Init_Ctrl[8].val[0] = 0;
+
+	state->Init_Ctrl[9].Ctrl_Num = AGC_IF ;
+	state->Init_Ctrl[9].size = 4 ;
+	state->Init_Ctrl[9].addr[0] = 76;
+	state->Init_Ctrl[9].bit[0] = 0;
+	state->Init_Ctrl[9].val[0] = 1;
+	state->Init_Ctrl[9].addr[1] = 76;
+	state->Init_Ctrl[9].bit[1] = 1;
+	state->Init_Ctrl[9].val[1] = 1;
+	state->Init_Ctrl[9].addr[2] = 76;
+	state->Init_Ctrl[9].bit[2] = 2;
+	state->Init_Ctrl[9].val[2] = 0;
+	state->Init_Ctrl[9].addr[3] = 76;
+	state->Init_Ctrl[9].bit[3] = 3;
+	state->Init_Ctrl[9].val[3] = 1;
+
+	state->Init_Ctrl[10].Ctrl_Num = AGC_RF ;
+	state->Init_Ctrl[10].size = 4 ;
+	state->Init_Ctrl[10].addr[0] = 76;
+	state->Init_Ctrl[10].bit[0] = 4;
+	state->Init_Ctrl[10].val[0] = 1;
+	state->Init_Ctrl[10].addr[1] = 76;
+	state->Init_Ctrl[10].bit[1] = 5;
+	state->Init_Ctrl[10].val[1] = 1;
+	state->Init_Ctrl[10].addr[2] = 76;
+	state->Init_Ctrl[10].bit[2] = 6;
+	state->Init_Ctrl[10].val[2] = 0;
+	state->Init_Ctrl[10].addr[3] = 76;
+	state->Init_Ctrl[10].bit[3] = 7;
+	state->Init_Ctrl[10].val[3] = 1;
+
+	state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ;
+	state->Init_Ctrl[11].size = 5 ;
+	state->Init_Ctrl[11].addr[0] = 43;
+	state->Init_Ctrl[11].bit[0] = 3;
+	state->Init_Ctrl[11].val[0] = 0;
+	state->Init_Ctrl[11].addr[1] = 43;
+	state->Init_Ctrl[11].bit[1] = 4;
+	state->Init_Ctrl[11].val[1] = 0;
+	state->Init_Ctrl[11].addr[2] = 43;
+	state->Init_Ctrl[11].bit[2] = 5;
+	state->Init_Ctrl[11].val[2] = 0;
+	state->Init_Ctrl[11].addr[3] = 43;
+	state->Init_Ctrl[11].bit[3] = 6;
+	state->Init_Ctrl[11].val[3] = 1;
+	state->Init_Ctrl[11].addr[4] = 43;
+	state->Init_Ctrl[11].bit[4] = 7;
+	state->Init_Ctrl[11].val[4] = 0;
+
+	state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ;
+	state->Init_Ctrl[12].size = 6 ;
+	state->Init_Ctrl[12].addr[0] = 44;
+	state->Init_Ctrl[12].bit[0] = 2;
+	state->Init_Ctrl[12].val[0] = 0;
+	state->Init_Ctrl[12].addr[1] = 44;
+	state->Init_Ctrl[12].bit[1] = 3;
+	state->Init_Ctrl[12].val[1] = 0;
+	state->Init_Ctrl[12].addr[2] = 44;
+	state->Init_Ctrl[12].bit[2] = 4;
+	state->Init_Ctrl[12].val[2] = 0;
+	state->Init_Ctrl[12].addr[3] = 44;
+	state->Init_Ctrl[12].bit[3] = 5;
+	state->Init_Ctrl[12].val[3] = 1;
+	state->Init_Ctrl[12].addr[4] = 44;
+	state->Init_Ctrl[12].bit[4] = 6;
+	state->Init_Ctrl[12].val[4] = 0;
+	state->Init_Ctrl[12].addr[5] = 44;
+	state->Init_Ctrl[12].bit[5] = 7;
+	state->Init_Ctrl[12].val[5] = 0;
+
+	state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ;
+	state->Init_Ctrl[13].size = 7 ;
+	state->Init_Ctrl[13].addr[0] = 11;
+	state->Init_Ctrl[13].bit[0] = 0;
+	state->Init_Ctrl[13].val[0] = 1;
+	state->Init_Ctrl[13].addr[1] = 11;
+	state->Init_Ctrl[13].bit[1] = 1;
+	state->Init_Ctrl[13].val[1] = 0;
+	state->Init_Ctrl[13].addr[2] = 11;
+	state->Init_Ctrl[13].bit[2] = 2;
+	state->Init_Ctrl[13].val[2] = 0;
+	state->Init_Ctrl[13].addr[3] = 11;
+	state->Init_Ctrl[13].bit[3] = 3;
+	state->Init_Ctrl[13].val[3] = 1;
+	state->Init_Ctrl[13].addr[4] = 11;
+	state->Init_Ctrl[13].bit[4] = 4;
+	state->Init_Ctrl[13].val[4] = 1;
+	state->Init_Ctrl[13].addr[5] = 11;
+	state->Init_Ctrl[13].bit[5] = 5;
+	state->Init_Ctrl[13].val[5] = 0;
+	state->Init_Ctrl[13].addr[6] = 11;
+	state->Init_Ctrl[13].bit[6] = 6;
+	state->Init_Ctrl[13].val[6] = 0;
+
+	state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ;
+	state->Init_Ctrl[14].size = 16 ;
+	state->Init_Ctrl[14].addr[0] = 13;
+	state->Init_Ctrl[14].bit[0] = 0;
+	state->Init_Ctrl[14].val[0] = 0;
+	state->Init_Ctrl[14].addr[1] = 13;
+	state->Init_Ctrl[14].bit[1] = 1;
+	state->Init_Ctrl[14].val[1] = 0;
+	state->Init_Ctrl[14].addr[2] = 13;
+	state->Init_Ctrl[14].bit[2] = 2;
+	state->Init_Ctrl[14].val[2] = 0;
+	state->Init_Ctrl[14].addr[3] = 13;
+	state->Init_Ctrl[14].bit[3] = 3;
+	state->Init_Ctrl[14].val[3] = 0;
+	state->Init_Ctrl[14].addr[4] = 13;
+	state->Init_Ctrl[14].bit[4] = 4;
+	state->Init_Ctrl[14].val[4] = 0;
+	state->Init_Ctrl[14].addr[5] = 13;
+	state->Init_Ctrl[14].bit[5] = 5;
+	state->Init_Ctrl[14].val[5] = 0;
+	state->Init_Ctrl[14].addr[6] = 13;
+	state->Init_Ctrl[14].bit[6] = 6;
+	state->Init_Ctrl[14].val[6] = 0;
+	state->Init_Ctrl[14].addr[7] = 13;
+	state->Init_Ctrl[14].bit[7] = 7;
+	state->Init_Ctrl[14].val[7] = 0;
+	state->Init_Ctrl[14].addr[8] = 12;
+	state->Init_Ctrl[14].bit[8] = 0;
+	state->Init_Ctrl[14].val[8] = 0;
+	state->Init_Ctrl[14].addr[9] = 12;
+	state->Init_Ctrl[14].bit[9] = 1;
+	state->Init_Ctrl[14].val[9] = 0;
+	state->Init_Ctrl[14].addr[10] = 12;
+	state->Init_Ctrl[14].bit[10] = 2;
+	state->Init_Ctrl[14].val[10] = 0;
+	state->Init_Ctrl[14].addr[11] = 12;
+	state->Init_Ctrl[14].bit[11] = 3;
+	state->Init_Ctrl[14].val[11] = 0;
+	state->Init_Ctrl[14].addr[12] = 12;
+	state->Init_Ctrl[14].bit[12] = 4;
+	state->Init_Ctrl[14].val[12] = 0;
+	state->Init_Ctrl[14].addr[13] = 12;
+	state->Init_Ctrl[14].bit[13] = 5;
+	state->Init_Ctrl[14].val[13] = 1;
+	state->Init_Ctrl[14].addr[14] = 12;
+	state->Init_Ctrl[14].bit[14] = 6;
+	state->Init_Ctrl[14].val[14] = 1;
+	state->Init_Ctrl[14].addr[15] = 12;
+	state->Init_Ctrl[14].bit[15] = 7;
+	state->Init_Ctrl[14].val[15] = 0;
+
+	state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ;
+	state->Init_Ctrl[15].size = 3 ;
+	state->Init_Ctrl[15].addr[0] = 147;
+	state->Init_Ctrl[15].bit[0] = 2;
+	state->Init_Ctrl[15].val[0] = 0;
+	state->Init_Ctrl[15].addr[1] = 147;
+	state->Init_Ctrl[15].bit[1] = 3;
+	state->Init_Ctrl[15].val[1] = 1;
+	state->Init_Ctrl[15].addr[2] = 147;
+	state->Init_Ctrl[15].bit[2] = 4;
+	state->Init_Ctrl[15].val[2] = 1;
+
+	state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ;
+	state->Init_Ctrl[16].size = 2 ;
+	state->Init_Ctrl[16].addr[0] = 147;
+	state->Init_Ctrl[16].bit[0] = 0;
+	state->Init_Ctrl[16].val[0] = 0;
+	state->Init_Ctrl[16].addr[1] = 147;
+	state->Init_Ctrl[16].bit[1] = 1;
+	state->Init_Ctrl[16].val[1] = 1;
+
+	state->Init_Ctrl[17].Ctrl_Num = EN_AAF ;
+	state->Init_Ctrl[17].size = 1 ;
+	state->Init_Ctrl[17].addr[0] = 147;
+	state->Init_Ctrl[17].bit[0] = 7;
+	state->Init_Ctrl[17].val[0] = 0;
+
+	state->Init_Ctrl[18].Ctrl_Num = EN_3P ;
+	state->Init_Ctrl[18].size = 1 ;
+	state->Init_Ctrl[18].addr[0] = 147;
+	state->Init_Ctrl[18].bit[0] = 6;
+	state->Init_Ctrl[18].val[0] = 0;
+
+	state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ;
+	state->Init_Ctrl[19].size = 1 ;
+	state->Init_Ctrl[19].addr[0] = 156;
+	state->Init_Ctrl[19].bit[0] = 0;
+	state->Init_Ctrl[19].val[0] = 0;
+
+	state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ;
+	state->Init_Ctrl[20].size = 1 ;
+	state->Init_Ctrl[20].addr[0] = 147;
+	state->Init_Ctrl[20].bit[0] = 5;
+	state->Init_Ctrl[20].val[0] = 0;
+
+	state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ;
+	state->Init_Ctrl[21].size = 1 ;
+	state->Init_Ctrl[21].addr[0] = 137;
+	state->Init_Ctrl[21].bit[0] = 4;
+	state->Init_Ctrl[21].val[0] = 0;
+
+	state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ;
+	state->Init_Ctrl[22].size = 1 ;
+	state->Init_Ctrl[22].addr[0] = 137;
+	state->Init_Ctrl[22].bit[0] = 7;
+	state->Init_Ctrl[22].val[0] = 0;
+
+	state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ;
+	state->Init_Ctrl[23].size = 1 ;
+	state->Init_Ctrl[23].addr[0] = 91;
+	state->Init_Ctrl[23].bit[0] = 5;
+	state->Init_Ctrl[23].val[0] = 1;
+
+	state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ;
+	state->Init_Ctrl[24].size = 1 ;
+	state->Init_Ctrl[24].addr[0] = 43;
+	state->Init_Ctrl[24].bit[0] = 0;
+	state->Init_Ctrl[24].val[0] = 1;
+
+	state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ;
+	state->Init_Ctrl[25].size = 2 ;
+	state->Init_Ctrl[25].addr[0] = 22;
+	state->Init_Ctrl[25].bit[0] = 0;
+	state->Init_Ctrl[25].val[0] = 1;
+	state->Init_Ctrl[25].addr[1] = 22;
+	state->Init_Ctrl[25].bit[1] = 1;
+	state->Init_Ctrl[25].val[1] = 1;
+
+	state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ;
+	state->Init_Ctrl[26].size = 1 ;
+	state->Init_Ctrl[26].addr[0] = 134;
+	state->Init_Ctrl[26].bit[0] = 2;
+	state->Init_Ctrl[26].val[0] = 0;
+
+	state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ;
+	state->Init_Ctrl[27].size = 1 ;
+	state->Init_Ctrl[27].addr[0] = 137;
+	state->Init_Ctrl[27].bit[0] = 3;
+	state->Init_Ctrl[27].val[0] = 0;
+
+	state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ;
+	state->Init_Ctrl[28].size = 1 ;
+	state->Init_Ctrl[28].addr[0] = 77;
+	state->Init_Ctrl[28].bit[0] = 7;
+	state->Init_Ctrl[28].val[0] = 0;
+
+	state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ;
+	state->Init_Ctrl[29].size = 1 ;
+	state->Init_Ctrl[29].addr[0] = 166;
+	state->Init_Ctrl[29].bit[0] = 7;
+	state->Init_Ctrl[29].val[0] = 1;
+
+	state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ;
+	state->Init_Ctrl[30].size = 3 ;
+	state->Init_Ctrl[30].addr[0] = 166;
+	state->Init_Ctrl[30].bit[0] = 0;
+	state->Init_Ctrl[30].val[0] = 0;
+	state->Init_Ctrl[30].addr[1] = 166;
+	state->Init_Ctrl[30].bit[1] = 1;
+	state->Init_Ctrl[30].val[1] = 1;
+	state->Init_Ctrl[30].addr[2] = 166;
+	state->Init_Ctrl[30].bit[2] = 2;
+	state->Init_Ctrl[30].val[2] = 1;
+
+	state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ;
+	state->Init_Ctrl[31].size = 3 ;
+	state->Init_Ctrl[31].addr[0] = 166;
+	state->Init_Ctrl[31].bit[0] = 3;
+	state->Init_Ctrl[31].val[0] = 1;
+	state->Init_Ctrl[31].addr[1] = 166;
+	state->Init_Ctrl[31].bit[1] = 4;
+	state->Init_Ctrl[31].val[1] = 0;
+	state->Init_Ctrl[31].addr[2] = 166;
+	state->Init_Ctrl[31].bit[2] = 5;
+	state->Init_Ctrl[31].val[2] = 1;
+
+	state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ;
+	state->Init_Ctrl[32].size = 3 ;
+	state->Init_Ctrl[32].addr[0] = 167;
+	state->Init_Ctrl[32].bit[0] = 0;
+	state->Init_Ctrl[32].val[0] = 1;
+	state->Init_Ctrl[32].addr[1] = 167;
+	state->Init_Ctrl[32].bit[1] = 1;
+	state->Init_Ctrl[32].val[1] = 1;
+	state->Init_Ctrl[32].addr[2] = 167;
+	state->Init_Ctrl[32].bit[2] = 2;
+	state->Init_Ctrl[32].val[2] = 0;
+
+	state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ;
+	state->Init_Ctrl[33].size = 4 ;
+	state->Init_Ctrl[33].addr[0] = 168;
+	state->Init_Ctrl[33].bit[0] = 0;
+	state->Init_Ctrl[33].val[0] = 0;
+	state->Init_Ctrl[33].addr[1] = 168;
+	state->Init_Ctrl[33].bit[1] = 1;
+	state->Init_Ctrl[33].val[1] = 1;
+	state->Init_Ctrl[33].addr[2] = 168;
+	state->Init_Ctrl[33].bit[2] = 2;
+	state->Init_Ctrl[33].val[2] = 0;
+	state->Init_Ctrl[33].addr[3] = 168;
+	state->Init_Ctrl[33].bit[3] = 3;
+	state->Init_Ctrl[33].val[3] = 0;
+
+	state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ;
+	state->Init_Ctrl[34].size = 4 ;
+	state->Init_Ctrl[34].addr[0] = 168;
+	state->Init_Ctrl[34].bit[0] = 4;
+	state->Init_Ctrl[34].val[0] = 1;
+	state->Init_Ctrl[34].addr[1] = 168;
+	state->Init_Ctrl[34].bit[1] = 5;
+	state->Init_Ctrl[34].val[1] = 1;
+	state->Init_Ctrl[34].addr[2] = 168;
+	state->Init_Ctrl[34].bit[2] = 6;
+	state->Init_Ctrl[34].val[2] = 1;
+	state->Init_Ctrl[34].addr[3] = 168;
+	state->Init_Ctrl[34].bit[3] = 7;
+	state->Init_Ctrl[34].val[3] = 1;
+
+	state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ;
+	state->Init_Ctrl[35].size = 1 ;
+	state->Init_Ctrl[35].addr[0] = 135;
+	state->Init_Ctrl[35].bit[0] = 0;
+	state->Init_Ctrl[35].val[0] = 0;
+
+	state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ;
+	state->Init_Ctrl[36].size = 1 ;
+	state->Init_Ctrl[36].addr[0] = 56;
+	state->Init_Ctrl[36].bit[0] = 3;
+	state->Init_Ctrl[36].val[0] = 0;
+
+	state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ;
+	state->Init_Ctrl[37].size = 7 ;
+	state->Init_Ctrl[37].addr[0] = 59;
+	state->Init_Ctrl[37].bit[0] = 1;
+	state->Init_Ctrl[37].val[0] = 0;
+	state->Init_Ctrl[37].addr[1] = 59;
+	state->Init_Ctrl[37].bit[1] = 2;
+	state->Init_Ctrl[37].val[1] = 0;
+	state->Init_Ctrl[37].addr[2] = 59;
+	state->Init_Ctrl[37].bit[2] = 3;
+	state->Init_Ctrl[37].val[2] = 0;
+	state->Init_Ctrl[37].addr[3] = 59;
+	state->Init_Ctrl[37].bit[3] = 4;
+	state->Init_Ctrl[37].val[3] = 0;
+	state->Init_Ctrl[37].addr[4] = 59;
+	state->Init_Ctrl[37].bit[4] = 5;
+	state->Init_Ctrl[37].val[4] = 0;
+	state->Init_Ctrl[37].addr[5] = 59;
+	state->Init_Ctrl[37].bit[5] = 6;
+	state->Init_Ctrl[37].val[5] = 0;
+	state->Init_Ctrl[37].addr[6] = 59;
+	state->Init_Ctrl[37].bit[6] = 7;
+	state->Init_Ctrl[37].val[6] = 0;
+
+	state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ;
+	state->Init_Ctrl[38].size = 6 ;
+	state->Init_Ctrl[38].addr[0] = 32;
+	state->Init_Ctrl[38].bit[0] = 2;
+	state->Init_Ctrl[38].val[0] = 0;
+	state->Init_Ctrl[38].addr[1] = 32;
+	state->Init_Ctrl[38].bit[1] = 3;
+	state->Init_Ctrl[38].val[1] = 0;
+	state->Init_Ctrl[38].addr[2] = 32;
+	state->Init_Ctrl[38].bit[2] = 4;
+	state->Init_Ctrl[38].val[2] = 0;
+	state->Init_Ctrl[38].addr[3] = 32;
+	state->Init_Ctrl[38].bit[3] = 5;
+	state->Init_Ctrl[38].val[3] = 0;
+	state->Init_Ctrl[38].addr[4] = 32;
+	state->Init_Ctrl[38].bit[4] = 6;
+	state->Init_Ctrl[38].val[4] = 1;
+	state->Init_Ctrl[38].addr[5] = 32;
+	state->Init_Ctrl[38].bit[5] = 7;
+	state->Init_Ctrl[38].val[5] = 0;
+
+	state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ;
+	state->Init_Ctrl[39].size = 1 ;
+	state->Init_Ctrl[39].addr[0] = 25;
+	state->Init_Ctrl[39].bit[0] = 3;
+	state->Init_Ctrl[39].val[0] = 1;
+
+
+	state->CH_Ctrl_Num = CHCTRL_NUM ;
+
+	state->CH_Ctrl[0].Ctrl_Num = DN_POLY ;
+	state->CH_Ctrl[0].size = 2 ;
+	state->CH_Ctrl[0].addr[0] = 68;
+	state->CH_Ctrl[0].bit[0] = 6;
+	state->CH_Ctrl[0].val[0] = 1;
+	state->CH_Ctrl[0].addr[1] = 68;
+	state->CH_Ctrl[0].bit[1] = 7;
+	state->CH_Ctrl[0].val[1] = 1;
+
+	state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ;
+	state->CH_Ctrl[1].size = 2 ;
+	state->CH_Ctrl[1].addr[0] = 70;
+	state->CH_Ctrl[1].bit[0] = 6;
+	state->CH_Ctrl[1].val[0] = 1;
+	state->CH_Ctrl[1].addr[1] = 70;
+	state->CH_Ctrl[1].bit[1] = 7;
+	state->CH_Ctrl[1].val[1] = 0;
+
+	state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ;
+	state->CH_Ctrl[2].size = 9 ;
+	state->CH_Ctrl[2].addr[0] = 69;
+	state->CH_Ctrl[2].bit[0] = 5;
+	state->CH_Ctrl[2].val[0] = 0;
+	state->CH_Ctrl[2].addr[1] = 69;
+	state->CH_Ctrl[2].bit[1] = 6;
+	state->CH_Ctrl[2].val[1] = 0;
+	state->CH_Ctrl[2].addr[2] = 69;
+	state->CH_Ctrl[2].bit[2] = 7;
+	state->CH_Ctrl[2].val[2] = 0;
+	state->CH_Ctrl[2].addr[3] = 68;
+	state->CH_Ctrl[2].bit[3] = 0;
+	state->CH_Ctrl[2].val[3] = 0;
+	state->CH_Ctrl[2].addr[4] = 68;
+	state->CH_Ctrl[2].bit[4] = 1;
+	state->CH_Ctrl[2].val[4] = 0;
+	state->CH_Ctrl[2].addr[5] = 68;
+	state->CH_Ctrl[2].bit[5] = 2;
+	state->CH_Ctrl[2].val[5] = 0;
+	state->CH_Ctrl[2].addr[6] = 68;
+	state->CH_Ctrl[2].bit[6] = 3;
+	state->CH_Ctrl[2].val[6] = 0;
+	state->CH_Ctrl[2].addr[7] = 68;
+	state->CH_Ctrl[2].bit[7] = 4;
+	state->CH_Ctrl[2].val[7] = 0;
+	state->CH_Ctrl[2].addr[8] = 68;
+	state->CH_Ctrl[2].bit[8] = 5;
+	state->CH_Ctrl[2].val[8] = 0;
+
+	state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ;
+	state->CH_Ctrl[3].size = 1 ;
+	state->CH_Ctrl[3].addr[0] = 70;
+	state->CH_Ctrl[3].bit[0] = 5;
+	state->CH_Ctrl[3].val[0] = 0;
+
+	state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ;
+	state->CH_Ctrl[4].size = 3 ;
+	state->CH_Ctrl[4].addr[0] = 73;
+	state->CH_Ctrl[4].bit[0] = 4;
+	state->CH_Ctrl[4].val[0] = 0;
+	state->CH_Ctrl[4].addr[1] = 73;
+	state->CH_Ctrl[4].bit[1] = 5;
+	state->CH_Ctrl[4].val[1] = 1;
+	state->CH_Ctrl[4].addr[2] = 73;
+	state->CH_Ctrl[4].bit[2] = 6;
+	state->CH_Ctrl[4].val[2] = 0;
+
+	state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ;
+	state->CH_Ctrl[5].size = 4 ;
+	state->CH_Ctrl[5].addr[0] = 70;
+	state->CH_Ctrl[5].bit[0] = 0;
+	state->CH_Ctrl[5].val[0] = 0;
+	state->CH_Ctrl[5].addr[1] = 70;
+	state->CH_Ctrl[5].bit[1] = 1;
+	state->CH_Ctrl[5].val[1] = 0;
+	state->CH_Ctrl[5].addr[2] = 70;
+	state->CH_Ctrl[5].bit[2] = 2;
+	state->CH_Ctrl[5].val[2] = 0;
+	state->CH_Ctrl[5].addr[3] = 70;
+	state->CH_Ctrl[5].bit[3] = 3;
+	state->CH_Ctrl[5].val[3] = 0;
+
+	state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ;
+	state->CH_Ctrl[6].size = 1 ;
+	state->CH_Ctrl[6].addr[0] = 70;
+	state->CH_Ctrl[6].bit[0] = 4;
+	state->CH_Ctrl[6].val[0] = 1;
+
+	state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ;
+	state->CH_Ctrl[7].size = 1 ;
+	state->CH_Ctrl[7].addr[0] = 111;
+	state->CH_Ctrl[7].bit[0] = 4;
+	state->CH_Ctrl[7].val[0] = 0;
+
+	state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ;
+	state->CH_Ctrl[8].size = 1 ;
+	state->CH_Ctrl[8].addr[0] = 111;
+	state->CH_Ctrl[8].bit[0] = 7;
+	state->CH_Ctrl[8].val[0] = 1;
+
+	state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ;
+	state->CH_Ctrl[9].size = 1 ;
+	state->CH_Ctrl[9].addr[0] = 111;
+	state->CH_Ctrl[9].bit[0] = 6;
+	state->CH_Ctrl[9].val[0] = 1;
+
+	state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ;
+	state->CH_Ctrl[10].size = 1 ;
+	state->CH_Ctrl[10].addr[0] = 111;
+	state->CH_Ctrl[10].bit[0] = 5;
+	state->CH_Ctrl[10].val[0] = 0;
+
+	state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ;
+	state->CH_Ctrl[11].size = 2 ;
+	state->CH_Ctrl[11].addr[0] = 110;
+	state->CH_Ctrl[11].bit[0] = 0;
+	state->CH_Ctrl[11].val[0] = 1;
+	state->CH_Ctrl[11].addr[1] = 110;
+	state->CH_Ctrl[11].bit[1] = 1;
+	state->CH_Ctrl[11].val[1] = 0;
+
+	state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ;
+	state->CH_Ctrl[12].size = 3 ;
+	state->CH_Ctrl[12].addr[0] = 69;
+	state->CH_Ctrl[12].bit[0] = 2;
+	state->CH_Ctrl[12].val[0] = 0;
+	state->CH_Ctrl[12].addr[1] = 69;
+	state->CH_Ctrl[12].bit[1] = 3;
+	state->CH_Ctrl[12].val[1] = 0;
+	state->CH_Ctrl[12].addr[2] = 69;
+	state->CH_Ctrl[12].bit[2] = 4;
+	state->CH_Ctrl[12].val[2] = 0;
+
+	state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ;
+	state->CH_Ctrl[13].size = 6 ;
+	state->CH_Ctrl[13].addr[0] = 110;
+	state->CH_Ctrl[13].bit[0] = 2;
+	state->CH_Ctrl[13].val[0] = 0;
+	state->CH_Ctrl[13].addr[1] = 110;
+	state->CH_Ctrl[13].bit[1] = 3;
+	state->CH_Ctrl[13].val[1] = 0;
+	state->CH_Ctrl[13].addr[2] = 110;
+	state->CH_Ctrl[13].bit[2] = 4;
+	state->CH_Ctrl[13].val[2] = 0;
+	state->CH_Ctrl[13].addr[3] = 110;
+	state->CH_Ctrl[13].bit[3] = 5;
+	state->CH_Ctrl[13].val[3] = 0;
+	state->CH_Ctrl[13].addr[4] = 110;
+	state->CH_Ctrl[13].bit[4] = 6;
+	state->CH_Ctrl[13].val[4] = 0;
+	state->CH_Ctrl[13].addr[5] = 110;
+	state->CH_Ctrl[13].bit[5] = 7;
+	state->CH_Ctrl[13].val[5] = 1;
+
+	state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ;
+	state->CH_Ctrl[14].size = 7 ;
+	state->CH_Ctrl[14].addr[0] = 14;
+	state->CH_Ctrl[14].bit[0] = 0;
+	state->CH_Ctrl[14].val[0] = 0;
+	state->CH_Ctrl[14].addr[1] = 14;
+	state->CH_Ctrl[14].bit[1] = 1;
+	state->CH_Ctrl[14].val[1] = 0;
+	state->CH_Ctrl[14].addr[2] = 14;
+	state->CH_Ctrl[14].bit[2] = 2;
+	state->CH_Ctrl[14].val[2] = 0;
+	state->CH_Ctrl[14].addr[3] = 14;
+	state->CH_Ctrl[14].bit[3] = 3;
+	state->CH_Ctrl[14].val[3] = 0;
+	state->CH_Ctrl[14].addr[4] = 14;
+	state->CH_Ctrl[14].bit[4] = 4;
+	state->CH_Ctrl[14].val[4] = 0;
+	state->CH_Ctrl[14].addr[5] = 14;
+	state->CH_Ctrl[14].bit[5] = 5;
+	state->CH_Ctrl[14].val[5] = 0;
+	state->CH_Ctrl[14].addr[6] = 14;
+	state->CH_Ctrl[14].bit[6] = 6;
+	state->CH_Ctrl[14].val[6] = 0;
+
+	state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ;
+	state->CH_Ctrl[15].size = 18 ;
+	state->CH_Ctrl[15].addr[0] = 17;
+	state->CH_Ctrl[15].bit[0] = 6;
+	state->CH_Ctrl[15].val[0] = 0;
+	state->CH_Ctrl[15].addr[1] = 17;
+	state->CH_Ctrl[15].bit[1] = 7;
+	state->CH_Ctrl[15].val[1] = 0;
+	state->CH_Ctrl[15].addr[2] = 16;
+	state->CH_Ctrl[15].bit[2] = 0;
+	state->CH_Ctrl[15].val[2] = 0;
+	state->CH_Ctrl[15].addr[3] = 16;
+	state->CH_Ctrl[15].bit[3] = 1;
+	state->CH_Ctrl[15].val[3] = 0;
+	state->CH_Ctrl[15].addr[4] = 16;
+	state->CH_Ctrl[15].bit[4] = 2;
+	state->CH_Ctrl[15].val[4] = 0;
+	state->CH_Ctrl[15].addr[5] = 16;
+	state->CH_Ctrl[15].bit[5] = 3;
+	state->CH_Ctrl[15].val[5] = 0;
+	state->CH_Ctrl[15].addr[6] = 16;
+	state->CH_Ctrl[15].bit[6] = 4;
+	state->CH_Ctrl[15].val[6] = 0;
+	state->CH_Ctrl[15].addr[7] = 16;
+	state->CH_Ctrl[15].bit[7] = 5;
+	state->CH_Ctrl[15].val[7] = 0;
+	state->CH_Ctrl[15].addr[8] = 16;
+	state->CH_Ctrl[15].bit[8] = 6;
+	state->CH_Ctrl[15].val[8] = 0;
+	state->CH_Ctrl[15].addr[9] = 16;
+	state->CH_Ctrl[15].bit[9] = 7;
+	state->CH_Ctrl[15].val[9] = 0;
+	state->CH_Ctrl[15].addr[10] = 15;
+	state->CH_Ctrl[15].bit[10] = 0;
+	state->CH_Ctrl[15].val[10] = 0;
+	state->CH_Ctrl[15].addr[11] = 15;
+	state->CH_Ctrl[15].bit[11] = 1;
+	state->CH_Ctrl[15].val[11] = 0;
+	state->CH_Ctrl[15].addr[12] = 15;
+	state->CH_Ctrl[15].bit[12] = 2;
+	state->CH_Ctrl[15].val[12] = 0;
+	state->CH_Ctrl[15].addr[13] = 15;
+	state->CH_Ctrl[15].bit[13] = 3;
+	state->CH_Ctrl[15].val[13] = 0;
+	state->CH_Ctrl[15].addr[14] = 15;
+	state->CH_Ctrl[15].bit[14] = 4;
+	state->CH_Ctrl[15].val[14] = 0;
+	state->CH_Ctrl[15].addr[15] = 15;
+	state->CH_Ctrl[15].bit[15] = 5;
+	state->CH_Ctrl[15].val[15] = 0;
+	state->CH_Ctrl[15].addr[16] = 15;
+	state->CH_Ctrl[15].bit[16] = 6;
+	state->CH_Ctrl[15].val[16] = 1;
+	state->CH_Ctrl[15].addr[17] = 15;
+	state->CH_Ctrl[15].bit[17] = 7;
+	state->CH_Ctrl[15].val[17] = 1;
+
+	state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ;
+	state->CH_Ctrl[16].size = 5 ;
+	state->CH_Ctrl[16].addr[0] = 112;
+	state->CH_Ctrl[16].bit[0] = 0;
+	state->CH_Ctrl[16].val[0] = 0;
+	state->CH_Ctrl[16].addr[1] = 112;
+	state->CH_Ctrl[16].bit[1] = 1;
+	state->CH_Ctrl[16].val[1] = 0;
+	state->CH_Ctrl[16].addr[2] = 112;
+	state->CH_Ctrl[16].bit[2] = 2;
+	state->CH_Ctrl[16].val[2] = 0;
+	state->CH_Ctrl[16].addr[3] = 112;
+	state->CH_Ctrl[16].bit[3] = 3;
+	state->CH_Ctrl[16].val[3] = 0;
+	state->CH_Ctrl[16].addr[4] = 112;
+	state->CH_Ctrl[16].bit[4] = 4;
+	state->CH_Ctrl[16].val[4] = 1;
+
+	state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ;
+	state->CH_Ctrl[17].size = 1 ;
+	state->CH_Ctrl[17].addr[0] = 14;
+	state->CH_Ctrl[17].bit[0] = 7;
+	state->CH_Ctrl[17].val[0] = 0;
+
+	state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ;
+	state->CH_Ctrl[18].size = 4 ;
+	state->CH_Ctrl[18].addr[0] = 107;
+	state->CH_Ctrl[18].bit[0] = 3;
+	state->CH_Ctrl[18].val[0] = 0;
+	state->CH_Ctrl[18].addr[1] = 107;
+	state->CH_Ctrl[18].bit[1] = 4;
+	state->CH_Ctrl[18].val[1] = 0;
+	state->CH_Ctrl[18].addr[2] = 107;
+	state->CH_Ctrl[18].bit[2] = 5;
+	state->CH_Ctrl[18].val[2] = 0;
+	state->CH_Ctrl[18].addr[3] = 107;
+	state->CH_Ctrl[18].bit[3] = 6;
+	state->CH_Ctrl[18].val[3] = 0;
+
+	state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ;
+	state->CH_Ctrl[19].size = 3 ;
+	state->CH_Ctrl[19].addr[0] = 107;
+	state->CH_Ctrl[19].bit[0] = 7;
+	state->CH_Ctrl[19].val[0] = 1;
+	state->CH_Ctrl[19].addr[1] = 106;
+	state->CH_Ctrl[19].bit[1] = 0;
+	state->CH_Ctrl[19].val[1] = 1;
+	state->CH_Ctrl[19].addr[2] = 106;
+	state->CH_Ctrl[19].bit[2] = 1;
+	state->CH_Ctrl[19].val[2] = 1;
+
+	state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ;
+	state->CH_Ctrl[20].size = 11 ;
+	state->CH_Ctrl[20].addr[0] = 109;
+	state->CH_Ctrl[20].bit[0] = 2;
+	state->CH_Ctrl[20].val[0] = 0;
+	state->CH_Ctrl[20].addr[1] = 109;
+	state->CH_Ctrl[20].bit[1] = 3;
+	state->CH_Ctrl[20].val[1] = 0;
+	state->CH_Ctrl[20].addr[2] = 109;
+	state->CH_Ctrl[20].bit[2] = 4;
+	state->CH_Ctrl[20].val[2] = 0;
+	state->CH_Ctrl[20].addr[3] = 109;
+	state->CH_Ctrl[20].bit[3] = 5;
+	state->CH_Ctrl[20].val[3] = 0;
+	state->CH_Ctrl[20].addr[4] = 109;
+	state->CH_Ctrl[20].bit[4] = 6;
+	state->CH_Ctrl[20].val[4] = 0;
+	state->CH_Ctrl[20].addr[5] = 109;
+	state->CH_Ctrl[20].bit[5] = 7;
+	state->CH_Ctrl[20].val[5] = 0;
+	state->CH_Ctrl[20].addr[6] = 108;
+	state->CH_Ctrl[20].bit[6] = 0;
+	state->CH_Ctrl[20].val[6] = 0;
+	state->CH_Ctrl[20].addr[7] = 108;
+	state->CH_Ctrl[20].bit[7] = 1;
+	state->CH_Ctrl[20].val[7] = 0;
+	state->CH_Ctrl[20].addr[8] = 108;
+	state->CH_Ctrl[20].bit[8] = 2;
+	state->CH_Ctrl[20].val[8] = 1;
+	state->CH_Ctrl[20].addr[9] = 108;
+	state->CH_Ctrl[20].bit[9] = 3;
+	state->CH_Ctrl[20].val[9] = 1;
+	state->CH_Ctrl[20].addr[10] = 108;
+	state->CH_Ctrl[20].bit[10] = 4;
+	state->CH_Ctrl[20].val[10] = 1;
+
+	state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ;
+	state->CH_Ctrl[21].size = 6 ;
+	state->CH_Ctrl[21].addr[0] = 106;
+	state->CH_Ctrl[21].bit[0] = 2;
+	state->CH_Ctrl[21].val[0] = 0;
+	state->CH_Ctrl[21].addr[1] = 106;
+	state->CH_Ctrl[21].bit[1] = 3;
+	state->CH_Ctrl[21].val[1] = 0;
+	state->CH_Ctrl[21].addr[2] = 106;
+	state->CH_Ctrl[21].bit[2] = 4;
+	state->CH_Ctrl[21].val[2] = 0;
+	state->CH_Ctrl[21].addr[3] = 106;
+	state->CH_Ctrl[21].bit[3] = 5;
+	state->CH_Ctrl[21].val[3] = 0;
+	state->CH_Ctrl[21].addr[4] = 106;
+	state->CH_Ctrl[21].bit[4] = 6;
+	state->CH_Ctrl[21].val[4] = 0;
+	state->CH_Ctrl[21].addr[5] = 106;
+	state->CH_Ctrl[21].bit[5] = 7;
+	state->CH_Ctrl[21].val[5] = 1;
+
+	state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ;
+	state->CH_Ctrl[22].size = 1 ;
+	state->CH_Ctrl[22].addr[0] = 138;
+	state->CH_Ctrl[22].bit[0] = 4;
+	state->CH_Ctrl[22].val[0] = 1;
+
+	state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ;
+	state->CH_Ctrl[23].size = 1 ;
+	state->CH_Ctrl[23].addr[0] = 17;
+	state->CH_Ctrl[23].bit[0] = 5;
+	state->CH_Ctrl[23].val[0] = 0;
+
+	state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ;
+	state->CH_Ctrl[24].size = 1 ;
+	state->CH_Ctrl[24].addr[0] = 111;
+	state->CH_Ctrl[24].bit[0] = 3;
+	state->CH_Ctrl[24].val[0] = 0;
+
+	state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ;
+	state->CH_Ctrl[25].size = 1 ;
+	state->CH_Ctrl[25].addr[0] = 112;
+	state->CH_Ctrl[25].bit[0] = 7;
+	state->CH_Ctrl[25].val[0] = 0;
+
+	state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ;
+	state->CH_Ctrl[26].size = 1 ;
+	state->CH_Ctrl[26].addr[0] = 136;
+	state->CH_Ctrl[26].bit[0] = 7;
+	state->CH_Ctrl[26].val[0] = 0;
+
+	state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ;
+	state->CH_Ctrl[27].size = 1 ;
+	state->CH_Ctrl[27].addr[0] = 149;
+	state->CH_Ctrl[27].bit[0] = 7;
+	state->CH_Ctrl[27].val[0] = 0;
+
+	state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ;
+	state->CH_Ctrl[28].size = 1 ;
+	state->CH_Ctrl[28].addr[0] = 149;
+	state->CH_Ctrl[28].bit[0] = 6;
+	state->CH_Ctrl[28].val[0] = 0;
+
+	state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ;
+	state->CH_Ctrl[29].size = 1 ;
+	state->CH_Ctrl[29].addr[0] = 149;
+	state->CH_Ctrl[29].bit[0] = 5;
+	state->CH_Ctrl[29].val[0] = 1;
+
+	state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ;
+	state->CH_Ctrl[30].size = 1 ;
+	state->CH_Ctrl[30].addr[0] = 149;
+	state->CH_Ctrl[30].bit[0] = 4;
+	state->CH_Ctrl[30].val[0] = 1;
+
+	state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ;
+	state->CH_Ctrl[31].size = 1 ;
+	state->CH_Ctrl[31].addr[0] = 149;
+	state->CH_Ctrl[31].bit[0] = 3;
+	state->CH_Ctrl[31].val[0] = 0;
+
+	state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ;
+	state->CH_Ctrl[32].size = 1 ;
+	state->CH_Ctrl[32].addr[0] = 93;
+	state->CH_Ctrl[32].bit[0] = 1;
+	state->CH_Ctrl[32].val[0] = 0;
+
+	state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ;
+	state->CH_Ctrl[33].size = 1 ;
+	state->CH_Ctrl[33].addr[0] = 93;
+	state->CH_Ctrl[33].bit[0] = 0;
+	state->CH_Ctrl[33].val[0] = 0;
+
+	state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ;
+	state->CH_Ctrl[34].size = 6 ;
+	state->CH_Ctrl[34].addr[0] = 92;
+	state->CH_Ctrl[34].bit[0] = 2;
+	state->CH_Ctrl[34].val[0] = 0;
+	state->CH_Ctrl[34].addr[1] = 92;
+	state->CH_Ctrl[34].bit[1] = 3;
+	state->CH_Ctrl[34].val[1] = 0;
+	state->CH_Ctrl[34].addr[2] = 92;
+	state->CH_Ctrl[34].bit[2] = 4;
+	state->CH_Ctrl[34].val[2] = 0;
+	state->CH_Ctrl[34].addr[3] = 92;
+	state->CH_Ctrl[34].bit[3] = 5;
+	state->CH_Ctrl[34].val[3] = 0;
+	state->CH_Ctrl[34].addr[4] = 92;
+	state->CH_Ctrl[34].bit[4] = 6;
+	state->CH_Ctrl[34].val[4] = 0;
+	state->CH_Ctrl[34].addr[5] = 92;
+	state->CH_Ctrl[34].bit[5] = 7;
+	state->CH_Ctrl[34].val[5] = 0;
+
+	state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ;
+	state->CH_Ctrl[35].size = 6 ;
+	state->CH_Ctrl[35].addr[0] = 93;
+	state->CH_Ctrl[35].bit[0] = 2;
+	state->CH_Ctrl[35].val[0] = 0;
+	state->CH_Ctrl[35].addr[1] = 93;
+	state->CH_Ctrl[35].bit[1] = 3;
+	state->CH_Ctrl[35].val[1] = 0;
+	state->CH_Ctrl[35].addr[2] = 93;
+	state->CH_Ctrl[35].bit[2] = 4;
+	state->CH_Ctrl[35].val[2] = 0;
+	state->CH_Ctrl[35].addr[3] = 93;
+	state->CH_Ctrl[35].bit[3] = 5;
+	state->CH_Ctrl[35].val[3] = 0;
+	state->CH_Ctrl[35].addr[4] = 93;
+	state->CH_Ctrl[35].bit[4] = 6;
+	state->CH_Ctrl[35].val[4] = 0;
+	state->CH_Ctrl[35].addr[5] = 93;
+	state->CH_Ctrl[35].bit[5] = 7;
+	state->CH_Ctrl[35].val[5] = 0;
+
+#ifdef _MXL_PRODUCTION
+	state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ;
+	state->CH_Ctrl[36].size = 1 ;
+	state->CH_Ctrl[36].addr[0] = 109;
+	state->CH_Ctrl[36].bit[0] = 1;
+	state->CH_Ctrl[36].val[0] = 1;
+
+	state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ;
+	state->CH_Ctrl[37].size = 2 ;
+	state->CH_Ctrl[37].addr[0] = 112;
+	state->CH_Ctrl[37].bit[0] = 5;
+	state->CH_Ctrl[37].val[0] = 0;
+	state->CH_Ctrl[37].addr[1] = 112;
+	state->CH_Ctrl[37].bit[1] = 6;
+	state->CH_Ctrl[37].val[1] = 0;
+
+	state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ;
+	state->CH_Ctrl[38].size = 1 ;
+	state->CH_Ctrl[38].addr[0] = 65;
+	state->CH_Ctrl[38].bit[0] = 1;
+	state->CH_Ctrl[38].val[0] = 0;
+#endif
+
+	return 0 ;
+}
+
+static void InitTunerControls(struct dvb_frontend *fe)
+{
+	MXL5005_RegisterInit(fe);
+	MXL5005_ControlInit(fe);
+#ifdef _MXL_INTERNAL
+	MXL5005_MXLControlInit(fe);
+#endif
+}
+
+static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
+	u8	Mode,		/* 0: Analog Mode ; 1: Digital Mode */
+	u8	IF_mode,	/* for Analog Mode, 0: zero IF; 1: low IF */
+	u32	Bandwidth,	/* filter  channel bandwidth (6, 7, 8) */
+	u32	IF_out,		/* Desired IF Out Frequency */
+	u32	Fxtal,		/* XTAL Frequency */
+	u8	AGC_Mode,	/* AGC Mode - Dual AGC: 0, Single AGC: 1 */
+	u16	TOP,		/* 0: Dual AGC; Value: take over point */
+	u16	IF_OUT_LOAD,	/* IF Out Load Resistor (200 / 300 Ohms) */
+	u8	CLOCK_OUT, 	/* 0: turn off clk out; 1: turn on clock out */
+	u8	DIV_OUT,	/* 0: Div-1; 1: Div-4 */
+	u8	CAPSELECT, 	/* 0: disable On-Chip pulling cap; 1: enable */
+	u8	EN_RSSI, 	/* 0: disable RSSI; 1: enable RSSI */
+
+	/* Modulation Type; */
+	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+	u8	Mod_Type,
+
+	/* Tracking Filter */
+	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+	u8	TF_Type
+	)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	state->Mode = Mode;
+	state->IF_Mode = IF_mode;
+	state->Chan_Bandwidth = Bandwidth;
+	state->IF_OUT = IF_out;
+	state->Fxtal = Fxtal;
+	state->AGC_Mode = AGC_Mode;
+	state->TOP = TOP;
+	state->IF_OUT_LOAD = IF_OUT_LOAD;
+	state->CLOCK_OUT = CLOCK_OUT;
+	state->DIV_OUT = DIV_OUT;
+	state->CAPSELECT = CAPSELECT;
+	state->EN_RSSI = EN_RSSI;
+	state->Mod_Type = Mod_Type;
+	state->TF_Type = TF_Type;
+
+	/* Initialize all the controls and registers */
+	InitTunerControls(fe);
+
+	/* Synthesizer LO frequency calculation */
+	MXL_SynthIFLO_Calc(fe);
+
+	return status;
+}
+
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	if (state->Mode == 1) /* Digital Mode */
+		state->IF_LO = state->IF_OUT;
+	else /* Analog Mode */ {
+		if (state->IF_Mode == 0) /* Analog Zero IF mode */
+			state->IF_LO = state->IF_OUT + 400000;
+		else /* Analog Low IF mode */
+			state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2;
+	}
+}
+
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+
+	if (state->Mode == 1) /* Digital Mode */ {
+			/* remove 20.48MHz setting for 2.6.10 */
+			state->RF_LO = state->RF_IN;
+			/* change for 2.6.6 */
+			state->TG_LO = state->RF_IN - 750000;
+	} else /* Analog Mode */ {
+		if (state->IF_Mode == 0) /* Analog Zero IF mode */ {
+			state->RF_LO = state->RF_IN - 400000;
+			state->TG_LO = state->RF_IN - 1750000;
+		} else /* Analog Low IF mode */ {
+			state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2;
+			state->TG_LO = state->RF_IN -
+				state->Chan_Bandwidth + 500000;
+		}
+	}
+}
+
+static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
+{
+	u16 status = 0;
+
+	status += MXL_ControlWrite(fe, OVERRIDE_1, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_2, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_3, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_4, 1);
+
+	return status;
+}
+
+static u16 MXL_BlockInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	status += MXL_OverwriteICDefault(fe);
+
+	/* Downconverter Control Dig Ana */
+	status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0);
+
+	/* Filter Control  Dig  Ana */
+	status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1);
+	status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2);
+	status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0);
+	status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1);
+	status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0);
+
+	/* Initialize Low-Pass Filter */
+	if (state->Mode) { /* Digital Mode */
+		switch (state->Chan_Bandwidth) {
+		case 8000000:
+			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0);
+			break;
+		case 7000000:
+			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2);
+			break;
+		case 6000000:
+			status += MXL_ControlWrite(fe,
+					BB_DLPF_BANDSEL, 3);
+			break;
+		}
+	} else { /* Analog Mode */
+		switch (state->Chan_Bandwidth) {
+		case 8000000:	/* Low Zero */
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 0 : 3));
+			break;
+		case 7000000:
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 1 : 4));
+			break;
+		case 6000000:
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 2 : 5));
+			break;
+		}
+	}
+
+	/* Charge Pump Control Dig  Ana */
+	status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8);
+	status += MXL_ControlWrite(fe,
+		RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1);
+	status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0);
+
+	/* AGC TOP Control */
+	if (state->AGC_Mode == 0) /* Dual AGC */ {
+		status += MXL_ControlWrite(fe, AGC_IF, 15);
+		status += MXL_ControlWrite(fe, AGC_RF, 15);
+	} else /*  Single AGC Mode Dig  Ana */
+		status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12);
+
+	if (state->TOP == 55) /* TOP == 5.5 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x0);
+
+	if (state->TOP == 72) /* TOP == 7.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x1);
+
+	if (state->TOP == 92) /* TOP == 9.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x2);
+
+	if (state->TOP == 110) /* TOP == 11.0 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x3);
+
+	if (state->TOP == 129) /* TOP == 12.9 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x4);
+
+	if (state->TOP == 147) /* TOP == 14.7 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x5);
+
+	if (state->TOP == 168) /* TOP == 16.8 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x6);
+
+	if (state->TOP == 194) /* TOP == 19.4 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x7);
+
+	if (state->TOP == 212) /* TOP == 21.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x9);
+
+	if (state->TOP == 232) /* TOP == 23.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xA);
+
+	if (state->TOP == 252) /* TOP == 25.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xB);
+
+	if (state->TOP == 271) /* TOP == 27.1 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xC);
+
+	if (state->TOP == 292) /* TOP == 29.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xD);
+
+	if (state->TOP == 317) /* TOP == 31.7 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xE);
+
+	if (state->TOP == 349) /* TOP == 34.9 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xF);
+
+	/* IF Synthesizer Control */
+	status += MXL_IFSynthInit(fe);
+
+	/* IF UpConverter Control */
+	if (state->IF_OUT_LOAD == 200) {
+		status += MXL_ControlWrite(fe, DRV_RES_SEL, 6);
+		status += MXL_ControlWrite(fe, I_DRIVER, 2);
+	}
+	if (state->IF_OUT_LOAD == 300) {
+		status += MXL_ControlWrite(fe, DRV_RES_SEL, 4);
+		status += MXL_ControlWrite(fe, I_DRIVER, 1);
+	}
+
+	/* Anti-Alias Filtering Control
+	 * initialise Anti-Aliasing Filter
+	 */
+	if (state->Mode) { /* Digital Mode */
+		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+		if ((state->IF_OUT == 36125000UL) ||
+			(state->IF_OUT == 36150000UL)) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+		}
+		if (state->IF_OUT > 36150000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 0);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+		}
+	} else { /* Analog Mode */
+		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+		if (state->IF_OUT > 5000000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 0);
+			status += MXL_ControlWrite(fe, EN_3P, 0);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 0);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+	}
+
+	/* Demod Clock Out */
+	if (state->CLOCK_OUT)
+		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1);
+	else
+		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0);
+
+	if (state->DIV_OUT == 1)
+		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1);
+	if (state->DIV_OUT == 0)
+		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0);
+
+	/* Crystal Control */
+	if (state->CAPSELECT)
+		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1);
+	else
+		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+		status += MXL_ControlWrite(fe, IF_SEL_DBL, 1);
+	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+		status += MXL_ControlWrite(fe, IF_SEL_DBL, 0);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3);
+	if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL)
+		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0);
+
+	/* Misc Controls */
+	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */
+		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0);
+	else
+		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1);
+
+	/* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */
+
+	/* Set TG_R_DIV */
+	status += MXL_ControlWrite(fe, TG_R_DIV,
+		MXL_Ceiling(state->Fxtal, 1000000));
+
+	/* Apply Default value to BB_INITSTATE_DLPF_TUNE */
+
+	/* RSSI Control */
+	if (state->EN_RSSI) {
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 0);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 12);
+	}
+
+	/* Modulation type bit settings
+	 * Override the control values preset
+	 */
+	if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ {
+		state->AGC_Mode = 1; /* Single AGC Mode */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 2);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+
+	}
+	if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ {
+		state->AGC_Mode = 1;	/* Single AGC Mode */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 2);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+		status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1);
+		/* Low Zero */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+	if (state->Mod_Type == MXL_QAM) /* QAM Mode */ {
+		state->Mode = MXL_DIGITAL_MODE;
+
+		/* state->AGC_Mode = 1; */ /* Single AGC Mode */
+
+		/* Disable RSSI */	/* change here for v2.6.5 */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+		/* change here for v2.6.5 */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+
+	}
+	if (state->Mod_Type == MXL_ANALOG_CABLE) {
+		/* Analog Cable Mode */
+		/* state->Mode = MXL_DIGITAL_MODE; */
+
+		state->AGC_Mode = 1; /* Single AGC Mode */
+
+		/* Disable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+		/* change for 2.6.3 */
+		status += MXL_ControlWrite(fe, AGC_IF, 1);
+		status += MXL_ControlWrite(fe, AGC_RF, 15);
+		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+
+	if (state->Mod_Type == MXL_ANALOG_OTA) {
+		/* Analog OTA Terrestrial mode add for 2.6.7 */
+		/* state->Mode = MXL_ANALOG_MODE; */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+
+	/* RSSI disable */
+	if (state->EN_RSSI == 0) {
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+	}
+
+	return status;
+}
+
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0 ;
+	u32	Fref = 0 ;
+	u32	Kdbl, intModVal ;
+	u32	fracModVal ;
+	Kdbl = 2 ;
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+		Kdbl = 2 ;
+	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+		Kdbl = 1 ;
+
+	/* IF Synthesizer Control */
+	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ {
+		if (state->IF_LO == 41000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 328000000UL ;
+		}
+		if (state->IF_LO == 47000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 376000000UL ;
+		}
+		if (state->IF_LO == 54000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 324000000UL ;
+		}
+		if (state->IF_LO == 60000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 39250000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 314000000UL ;
+		}
+		if (state->IF_LO == 39650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 317200000UL ;
+		}
+		if (state->IF_LO == 40150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 321200000UL ;
+		}
+		if (state->IF_LO == 40650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 325200000UL ;
+		}
+	}
+
+	if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) {
+		if (state->IF_LO == 57000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 342000000UL ;
+		}
+		if (state->IF_LO == 44000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352000000UL ;
+		}
+		if (state->IF_LO == 43750000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 350000000UL ;
+		}
+		if (state->IF_LO == 36650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 366500000UL ;
+		}
+		if (state->IF_LO == 36150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 361500000UL ;
+		}
+		if (state->IF_LO == 36000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 35250000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352500000UL ;
+		}
+		if (state->IF_LO == 34750000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 347500000UL ;
+		}
+		if (state->IF_LO == 6280000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 376800000UL ;
+		}
+		if (state->IF_LO == 5000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 4500000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 4570000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365600000UL ;
+		}
+		if (state->IF_LO == 4000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 57400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 344400000UL ;
+		}
+		if (state->IF_LO == 44400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 355200000UL ;
+		}
+		if (state->IF_LO == 44150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 353200000UL ;
+		}
+		if (state->IF_LO == 37050000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 370500000UL ;
+		}
+		if (state->IF_LO == 36550000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365500000UL ;
+		}
+		if (state->IF_LO == 36125000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 361250000UL ;
+		}
+		if (state->IF_LO == 6000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 5400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 324000000UL ;
+		}
+		if (state->IF_LO == 5380000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 322800000UL ;
+		}
+		if (state->IF_LO == 5200000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 374400000UL ;
+		}
+		if (state->IF_LO == 4900000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352800000UL ;
+		}
+		if (state->IF_LO == 4400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352000000UL ;
+		}
+		if (state->IF_LO == 4063000UL)  /* add for 2.6.8 */ {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365670000UL ;
+		}
+	}
+	/* CHCAL_INT_MOD_IF */
+	/* CHCAL_FRAC_MOD_IF */
+	intModVal = Fref / (state->Fxtal * Kdbl/2);
+	status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal);
+
+	fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) *
+		intModVal);
+
+	fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000);
+	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal);
+
+	return status ;
+}
+
+static u32 MXL_GetXtalInt(u32 Xtal_Freq)
+{
+	if ((Xtal_Freq % 1000000) == 0)
+		return (Xtal_Freq / 10000);
+	else
+		return (((Xtal_Freq / 1000000) + 1)*100);
+}
+
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+	u32 divider_val, E3, E4, E5, E5A;
+	u32 Fmax, Fmin, FmaxBin, FminBin;
+	u32 Kdbl_RF = 2;
+	u32 tg_divval;
+	u32 tg_lo;
+	u32 Xtal_Int;
+
+	u32 Fref_TG;
+	u32 Fvco;
+
+	Xtal_Int = MXL_GetXtalInt(state->Fxtal);
+
+	state->RF_IN = RF_Freq;
+
+	MXL_SynthRFTGLO_Calc(fe);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+		Kdbl_RF = 2;
+	if (state->Fxtal > 22000000 && state->Fxtal <= 32000000)
+		Kdbl_RF = 1;
+
+	/* Downconverter Controls
+	 * Look-Up Table Implementation for:
+	 *	DN_POLY
+	 *	DN_RFGAIN
+	 *	DN_CAP_RFLPF
+	 *	DN_EN_VHFUHFBAR
+	 *	DN_GAIN_ADJUST
+	 *  Change the boundary reference from RF_IN to RF_LO
+	 */
+	if (state->RF_LO < 40000000UL)
+		return -1;
+
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              2);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         423);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
+	}
+	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         222);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
+	}
+	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         147);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
+	}
+	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         9);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
+	}
+	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            1);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            2);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 900000000UL)
+		return -1;
+
+	/*	DN_IQTNBUF_AMP */
+	/*	DN_IQTNGNBFBIAS_BST */
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
+	}
+	if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
+	}
+
+	/*
+	 * Set RF Synth and LO Path Control
+	 *
+	 * Look-Up table implementation for:
+	 *	RFSYN_EN_OUTMUX
+	 *	RFSYN_SEL_VCO_OUT
+	 *	RFSYN_SEL_VCO_HI
+	 *  RFSYN_SEL_DIVM
+	 *	RFSYN_RF_DIV_BIAS
+	 *	DN_SEL_FREQ
+	 *
+	 * Set divider_val, Fmax, Fmix to use in Equations
+	 */
+	FminBin = 28000000UL ;
+	FmaxBin = 42500000UL ;
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 64 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 42500000UL ;
+	FmaxBin = 56000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 64 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 56000000UL ;
+	FmaxBin = 85000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 32 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 85000000UL ;
+	FmaxBin = 112000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 32 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 112000000UL ;
+	FmaxBin = 170000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
+		divider_val = 16 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 170000000UL ;
+	FmaxBin = 225000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
+		divider_val = 16 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 225000000UL ;
+	FmaxBin = 300000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         4);
+		divider_val = 8 ;
+		Fmax = 340000000UL ;
+		Fmin = FminBin ;
+	}
+	FminBin = 300000000UL ;
+	FmaxBin = 340000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = 225000000UL ;
+	}
+	FminBin = 340000000UL ;
+	FmaxBin = 450000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   2);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 450000000UL ;
+	FmaxBin = 680000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 680000000UL ;
+	FmaxBin = 900000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+
+	/*	CHCAL_INT_MOD_RF
+	 *	CHCAL_FRAC_MOD_RF
+	 *	RFSYN_LPF_R
+	 *	CHCAL_EN_INT_RF
+	 */
+	/* Equation E3 RFSYN_VCO_BIAS */
+	E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ;
+	status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3);
+
+	/* Equation E4 CHCAL_INT_MOD_RF */
+	E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000);
+	MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4);
+
+	/* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */
+	E5 = ((2<<17)*(state->RF_LO/10000*divider_val -
+		(E4*(2*state->Fxtal*Kdbl_RF)/10000))) /
+		(2*state->Fxtal*Kdbl_RF/10000);
+
+	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+
+	/* Equation E5A RFSYN_LPF_R */
+	E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ;
+	status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A);
+
+	/* Euqation E5B CHCAL_EN_INIT_RF */
+	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0));
+	/*if (E5 == 0)
+	 *	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1);
+	 *else
+	 *	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+	 */
+
+	/*
+	 * Set TG Synth
+	 *
+	 * Look-Up table implementation for:
+	 *	TG_LO_DIVVAL
+	 *	TG_LO_SELVAL
+	 *
+	 * Set divider_val, Fmax, Fmix to use in Equations
+	 */
+	if (state->TG_LO < 33000000UL)
+		return -1;
+
+	FminBin = 33000000UL ;
+	FmaxBin = 50000000UL ;
+	if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x6);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
+		divider_val = 36 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 50000000UL ;
+	FmaxBin = 67000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x1);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
+		divider_val = 24 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 67000000UL ;
+	FmaxBin = 100000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0xC);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 18 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 100000000UL ;
+	FmaxBin = 150000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 12 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 150000000UL ;
+	FmaxBin = 200000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 200000000UL ;
+	FmaxBin = 300000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
+		divider_val = 6 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 300000000UL ;
+	FmaxBin = 400000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 400000000UL ;
+	FmaxBin = 600000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
+		divider_val = 3 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 600000000UL ;
+	FmaxBin = 900000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
+		divider_val = 2 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+
+	/* TG_DIV_VAL */
+	tg_divval = (state->TG_LO*divider_val/100000) *
+		(MXL_Ceiling(state->Fxtal, 1000000) * 100) /
+		(state->Fxtal/1000);
+
+	status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval);
+
+	if (state->TG_LO > 600000000UL)
+		status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1);
+
+	Fmax = 1800000000UL ;
+	Fmin = 1200000000UL ;
+
+	/* prevent overflow of 32 bit unsigned integer, use
+	 * following equation. Edit for v2.6.4
+	 */
+	/* Fref_TF = Fref_TG * 1000 */
+	Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000);
+
+	/* Fvco = Fvco/10 */
+	Fvco = (state->TG_LO/10000) * divider_val * Fref_TG;
+
+	tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
+
+	/* below equation is same as above but much harder to debug.
+	 * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
+	 * ((state->TG_LO/10000)*divider_val *
+	 * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *
+	 * Xtal_Int/100) + 8;
+	 */
+
+	status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo);
+
+	/* add for 2.6.5 Special setting for QAM */
+	if (state->Mod_Type == MXL_QAM) {
+		if (state->RF_IN < 680000000)
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		else
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+	}
+
+	/* Off Chip Tracking Filter Control */
+	if (state->TF_Type == MXL_TF_OFF) {
+		/* Tracking Filter Off State; turn off all the banks */
+		status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+		status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */
+		status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */
+		status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */
+	}
+
+	if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ {
+		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 29);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 16);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 7);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_C_H) {
+
+		/* Tracking Filter type C-H for Hauppauge only */
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */
+
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_D_L) {
+
+		/* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		/* if UHF and terrestrial => Turn off Tracking Filter */
+		if (state->RF_IN >= 471000000 &&
+			(state->RF_IN - 471000000)%6000000 != 0) {
+			/* Turn off all the banks */
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, AGC_IF, 10);
+		} else {
+			/* if VHF or cable => Turn on Tracking Filter */
+			if (state->RF_IN >= 43000000 &&
+				state->RF_IN < 140000000) {
+
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 140000000 &&
+				state->RF_IN < 240000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 240000000 &&
+				state->RF_IN < 340000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 340000000 &&
+				state->RF_IN < 430000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 430000000 &&
+				state->RF_IN < 470000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 470000000 &&
+				state->RF_IN < 570000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 570000000 &&
+				state->RF_IN < 620000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 620000000 &&
+				state->RF_IN < 760000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 760000000 &&
+				state->RF_IN <= 900000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ {
+
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_F) {
+
+		/* Tracking Filter type F */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E_2) {
+
+		/* Tracking Filter type E_2 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_G) {
+
+		/* Tracking Filter type G add for v2.6.8 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) {
+
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E_NA) {
+
+		/* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		/* if UHF and terrestrial=> Turn off Tracking Filter */
+		if (state->RF_IN >= 471000000 &&
+			(state->RF_IN - 471000000)%6000000 != 0) {
+
+			/* Turn off all the banks */
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+
+			/* 2.6.12 Turn on RSSI */
+			status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+			status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+			status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+			status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+			/* RSSI reference point */
+			status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+			status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+			status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+
+			/* following parameter is from analog OTA mode,
+			 * can be change to seek better performance */
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		} else {
+		/* if VHF or Cable =>  Turn on Tracking Filter */
+
+		/* 2.6.12 Turn off RSSI */
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+
+		/* change back from above condition */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		}
+	}
+	return status ;
+}
+
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
+{
+	u16 status = 0;
+
+	if (GPIO_Num == 1)
+		status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1);
+
+	/* GPIO2 is not available */
+
+	if (GPIO_Num == 3) {
+		if (GPIO_Val == 1) {
+			status += MXL_ControlWrite(fe, GPIO_3, 0);
+			status += MXL_ControlWrite(fe, GPIO_3B, 0);
+		}
+		if (GPIO_Val == 0) {
+			status += MXL_ControlWrite(fe, GPIO_3, 1);
+			status += MXL_ControlWrite(fe, GPIO_3B, 1);
+		}
+		if (GPIO_Val == 3) { /* tri-state */
+			status += MXL_ControlWrite(fe, GPIO_3, 0);
+			status += MXL_ControlWrite(fe, GPIO_3B, 1);
+		}
+	}
+	if (GPIO_Num == 4) {
+		if (GPIO_Val == 1) {
+			status += MXL_ControlWrite(fe, GPIO_4, 0);
+			status += MXL_ControlWrite(fe, GPIO_4B, 0);
+		}
+		if (GPIO_Val == 0) {
+			status += MXL_ControlWrite(fe, GPIO_4, 1);
+			status += MXL_ControlWrite(fe, GPIO_4B, 1);
+		}
+		if (GPIO_Val == 3) { /* tri-state */
+			status += MXL_ControlWrite(fe, GPIO_4, 0);
+			status += MXL_ControlWrite(fe, GPIO_4B, 1);
+		}
+	}
+
+	return status;
+}
+
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
+{
+	u16 status = 0;
+
+	/* Will write ALL Matching Control Name */
+	/* Write Matching INIT Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 1);
+	/* Write Matching CH Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 2);
+#ifdef _MXL_INTERNAL
+	/* Write Matching MXL Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 3);
+#endif
+	return status;
+}
+
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+	u32 value, u16 controlGroup)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 i, j, k;
+	u32 highLimit;
+	u32 ctrlVal;
+
+	if (controlGroup == 1) /* Initial Control */ {
+
+		for (i = 0; i < state->Init_Ctrl_Num; i++) {
+
+			if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+				highLimit = 1 << state->Init_Ctrl[i].size;
+				if (value < highLimit) {
+					for (j = 0; j < state->Init_Ctrl[i].size; j++) {
+						state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]),
+							(u8)(state->Init_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->Init_Ctrl[i].size; k++)
+						ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+	if (controlGroup == 2) /* Chan change Control */ {
+
+		for (i = 0; i < state->CH_Ctrl_Num; i++) {
+
+			if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+				highLimit = 1 << state->CH_Ctrl[i].size;
+				if (value < highLimit) {
+					for (j = 0; j < state->CH_Ctrl[i].size; j++) {
+						state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]),
+							(u8)(state->CH_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->CH_Ctrl[i].size; k++)
+						ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+#ifdef _MXL_INTERNAL
+	if (controlGroup == 3) /* Maxlinear Control */ {
+
+		for (i = 0; i < state->MXL_Ctrl_Num; i++) {
+
+			if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+				highLimit = (1 << state->MXL_Ctrl[i].size);
+				if (value < highLimit) {
+					for (j = 0; j < state->MXL_Ctrl[i].size; j++) {
+						state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]),
+							(u8)(state->MXL_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+						ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+#endif
+	return 0 ; /* successful return */
+}
+
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int i ;
+
+	for (i = 0; i < 104; i++) {
+		if (RegNum == state->TunerRegs[i].Reg_Num) {
+			*RegVal = (u8)(state->TunerRegs[i].Reg_Val);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u32 ctrlVal ;
+	u16 i, k ;
+
+	for (i = 0; i < state->Init_Ctrl_Num ; i++) {
+
+		if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->Init_Ctrl[i].size; k++)
+				ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k);
+			*value = ctrlVal;
+			return 0;
+		}
+	}
+
+	for (i = 0; i < state->CH_Ctrl_Num ; i++) {
+
+		if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->CH_Ctrl[i].size; k++)
+				ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+			*value = ctrlVal;
+			return 0;
+
+		}
+	}
+
+#ifdef _MXL_INTERNAL
+	for (i = 0; i < state->MXL_Ctrl_Num ; i++) {
+
+		if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+				ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k);
+			*value = ctrlVal;
+			return 0;
+
+		}
+	}
+#endif
+	return 1;
+}
+
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+	u8 bitVal)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int i ;
+
+	const u8 AND_MAP[8] = {
+		0xFE, 0xFD, 0xFB, 0xF7,
+		0xEF, 0xDF, 0xBF, 0x7F } ;
+
+	const u8 OR_MAP[8] = {
+		0x01, 0x02, 0x04, 0x08,
+		0x10, 0x20, 0x40, 0x80 } ;
+
+	for (i = 0; i < state->TunerRegs_Num; i++) {
+		if (state->TunerRegs[i].Reg_Num == address) {
+			if (bitVal)
+				state->TunerRegs[i].Reg_Val |= OR_MAP[bit];
+			else
+				state->TunerRegs[i].Reg_Val &= AND_MAP[bit];
+			break ;
+		}
+	}
+}
+
+static u32 MXL_Ceiling(u32 value, u32 resolution)
+{
+	return (value/resolution + (value % resolution > 0 ? 1 : 0));
+}
+
+/* Retrieve the Initialzation Registers */
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count)
+{
+	u16 status = 0;
+	int i ;
+
+	u8 RegAddr[] = {
+		11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73,
+		76, 77, 91, 134, 135, 137, 147,
+		156, 166, 167, 168, 25 };
+
+	*count = sizeof(RegAddr) / sizeof(u8);
+
+	status += MXL_BlockInit(fe);
+
+	for (i = 0 ; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
+	int *count)
+{
+	u16 status = 0;
+	int i ;
+
+/* add 77, 166, 167, 168 register for 2.6.12 */
+#ifdef _MXL_PRODUCTION
+	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106,
+	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+#else
+	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106,
+	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+	/*
+	u8 RegAddr[171];
+	for (i = 0; i <= 170; i++)
+		RegAddr[i] = i;
+	*/
+#endif
+
+	*count = sizeof(RegAddr) / sizeof(u8);
+
+	for (i = 0 ; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count)
+{
+	u16 status = 0;
+	int i;
+
+	u8 RegAddr[] = {43, 136};
+
+	*count = sizeof(RegAddr) / sizeof(u8);
+
+	for (i = 0; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state)
+{
+	if (state == 1) /* Load_Start */
+		*MasterReg = 0xF3;
+	if (state == 2) /* Power_Down */
+		*MasterReg = 0x41;
+	if (state == 3) /* Synth_Reset */
+		*MasterReg = 0xB1;
+	if (state == 4) /* Seq_Off */
+		*MasterReg = 0xF1;
+
+	return 0;
+}
+
+#ifdef _MXL_PRODUCTION
+static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0 ;
+
+	if (VCO_Range == 1) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 180224);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 222822);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 229376);
+		}
+	}
+
+	if (VCO_Range == 2) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 16384);
+		}
+	}
+
+	if (VCO_Range == 3) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 173670);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 173670);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 245760);
+		}
+	}
+
+	if (VCO_Range == 4) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 212992);
+		}
+	}
+
+	return status;
+}
+
+static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	if (Hystersis == 1)
+		status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1);
+
+	return status;
+}
+#endif
+/* End: Reference driver code found in the Realtek driver that
+ * is copyright MaxLinear */
+
+/* ----------------------------------------------------------------
+ * Begin: Everything after here is new code to adapt the
+ * proprietary Realtek driver into a Linux API tuner.
+ * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ */
+static int mxl5005s_reset(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int ret = 0;
+
+	u8 buf[2] = { 0xff, 0x00 };
+	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mxl5005s I2C reset failed\n");
+		ret = -EREMOTEIO;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+/* Write a single byte to a single reg, latch the value if required by
+ * following the transaction with the latch byte.
+ */
+static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE };
+	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+			       .buf = buf, .len = 3 };
+
+	if (latch == 0)
+		msg.len = 2;
+
+	dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mxl5005s I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+	u8 *datatable, u8 len)
+{
+	int ret = 0, i;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	for (i = 0 ; i < len-1; i++) {
+		ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0);
+		if (ret < 0)
+			break;
+	}
+
+	ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+static int mxl5005s_init(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+	return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
+}
+
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+
+	u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	int TableLen;
+
+	dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth);
+
+	mxl5005s_reset(fe);
+
+	/* Tuner initialization stage 0 */
+	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+	AddrTable[0] = MASTER_CONTROL_ADDR;
+	ByteTable[0] |= state->config->AgcMasterByte;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+	mxl5005s_AssignTunerMode(fe, mod_type, bandwidth);
+
+	/* Tuner initialization stage 1 */
+	MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen);
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	return 0;
+}
+
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	struct mxl5005s_config *c = state->config;
+
+	InitTunerControls(fe);
+
+	/* Set MxL5005S parameters. */
+	MXL5005_TunerConfig(
+		fe,
+		c->mod_mode,
+		c->if_mode,
+		bandwidth,
+		c->if_freq,
+		c->xtal_freq,
+		c->agc_mode,
+		c->top,
+		c->output_load,
+		c->clock_out,
+		c->div_out,
+		c->cap_select,
+		c->rssi_enable,
+		mod_type,
+		c->tracking_filter);
+
+	return 0;
+}
+
+static int mxl5005s_set_params(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *params)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u32 req_mode, req_bw = 0;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (fe->ops.info.type == FE_ATSC) {
+		switch (params->u.vsb.modulation) {
+		case VSB_8:
+			req_mode = MXL_ATSC; break;
+		default:
+		case QAM_64:
+		case QAM_256:
+		case QAM_AUTO:
+			req_mode = MXL_QAM; break;
+		}
+	} else
+		req_mode = MXL_DVBT;
+
+	/* Change tuner for new modulation type if reqd */
+	if (req_mode != state->current_mode) {
+		switch (req_mode) {
+		case VSB_8:
+		case QAM_64:
+		case QAM_256:
+		case QAM_AUTO:
+			req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+			break;
+		default:
+			/* Assume DVB-T */
+			switch (params->u.ofdm.bandwidth) {
+			case BANDWIDTH_6_MHZ:
+				req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+				break;
+			case BANDWIDTH_7_MHZ:
+				req_bw  = MXL5005S_BANDWIDTH_7MHZ;
+				break;
+			case BANDWIDTH_AUTO:
+			case BANDWIDTH_8_MHZ:
+				req_bw  = MXL5005S_BANDWIDTH_8MHZ;
+				break;
+			}
+		}
+
+		state->current_mode = req_mode;
+		ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
+
+	} else
+		ret = 0;
+
+	if (ret == 0) {
+		dprintk(1, "%s() freq=%d\n", __func__, params->frequency);
+		ret = mxl5005s_SetRfFreqHz(fe, params->frequency);
+	}
+
+	return ret;
+}
+
+static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*frequency = state->RF_IN;
+
+	return 0;
+}
+
+static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*bandwidth = state->Chan_Bandwidth;
+
+	return 0;
+}
+
+static int mxl5005s_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mxl5005s_tuner_ops = {
+	.info = {
+		.name           = "MaxLinear MXL5005S",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mxl5005s_release,
+	.init          = mxl5005s_init,
+
+	.set_params    = mxl5005s_set_params,
+	.get_frequency = mxl5005s_get_frequency,
+	.get_bandwidth = mxl5005s_get_bandwidth,
+};
+
+struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+				     struct i2c_adapter *i2c,
+				     struct mxl5005s_config *config)
+{
+	struct mxl5005s_state *state = NULL;
+	dprintk(1, "%s()\n", __func__);
+
+	state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->frontend = fe;
+	state->config = config;
+	state->i2c = i2c;
+	state->current_mode = MXL_QAM;
+
+	printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
+		config->i2c_address);
+
+	memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+}
+EXPORT_SYMBOL(mxl5005s_attach);
+
+MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
new file mode 100644
index 0000000..396db15
--- /dev/null
+++ b/drivers/media/common/tuners/mxl5005s.h
@@ -0,0 +1,131 @@
+/*
+    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+    Copyright (C) 2008 MaxLinear
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __MXL5005S_H
+#define __MXL5005S_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct mxl5005s_config {
+
+	/* 7 bit i2c address */
+	u8 i2c_address;
+
+#define IF_FREQ_4570000HZ    4570000
+#define IF_FREQ_4571429HZ    4571429
+#define IF_FREQ_5380000HZ    5380000
+#define IF_FREQ_36000000HZ  36000000
+#define IF_FREQ_36125000HZ  36125000
+#define IF_FREQ_36166667HZ  36166667
+#define IF_FREQ_44000000HZ  44000000
+	u32 if_freq;
+
+#define CRYSTAL_FREQ_4000000HZ    4000000
+#define CRYSTAL_FREQ_16000000HZ  16000000
+#define CRYSTAL_FREQ_25000000HZ  25000000
+#define CRYSTAL_FREQ_28800000HZ  28800000
+	u32 xtal_freq;
+
+#define MXL_DUAL_AGC   0
+#define MXL_SINGLE_AGC 1
+	u8 agc_mode;
+
+#define MXL_TF_DEFAULT	0
+#define MXL_TF_OFF	1
+#define MXL_TF_C	2
+#define MXL_TF_C_H	3
+#define MXL_TF_D	4
+#define MXL_TF_D_L	5
+#define MXL_TF_E	6
+#define MXL_TF_F	7
+#define MXL_TF_E_2	8
+#define MXL_TF_E_NA	9
+#define MXL_TF_G	10
+	u8 tracking_filter;
+
+#define MXL_RSSI_DISABLE	0
+#define MXL_RSSI_ENABLE		1
+	u8 rssi_enable;
+
+#define MXL_CAP_SEL_DISABLE	0
+#define MXL_CAP_SEL_ENABLE	1
+	u8 cap_select;
+
+#define MXL_DIV_OUT_1	0
+#define MXL_DIV_OUT_4	1
+	u8 div_out;
+
+#define MXL_CLOCK_OUT_DISABLE	0
+#define MXL_CLOCK_OUT_ENABLE	1
+	u8 clock_out;
+
+#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200
+#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300
+	u32 output_load;
+
+#define MXL5005S_TOP_5P5   55
+#define MXL5005S_TOP_7P2   72
+#define MXL5005S_TOP_9P2   92
+#define MXL5005S_TOP_11P0 110
+#define MXL5005S_TOP_12P9 129
+#define MXL5005S_TOP_14P7 147
+#define MXL5005S_TOP_16P8 168
+#define MXL5005S_TOP_19P4 194
+#define MXL5005S_TOP_21P2 212
+#define MXL5005S_TOP_23P2 232
+#define MXL5005S_TOP_25P2 252
+#define MXL5005S_TOP_27P1 271
+#define MXL5005S_TOP_29P2 292
+#define MXL5005S_TOP_31P7 317
+#define MXL5005S_TOP_34P9 349
+	u32 top;
+
+#define MXL_ANALOG_MODE  0
+#define MXL_DIGITAL_MODE 1
+	u8 mod_mode;
+
+#define MXL_ZERO_IF 0
+#define MXL_LOW_IF  1
+	u8 if_mode;
+
+	/* Stuff I don't know what to do with */
+	u8 AgcMasterByte;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
+	(defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+					    struct i2c_adapter *i2c,
+					    struct mxl5005s_config *config);
+#else
+static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+					    struct i2c_adapter *i2c,
+					    struct mxl5005s_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MXL5005S */
+
+#endif /* __MXL5005S_H */
+
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index e27a762..42b5f5d 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -227,9 +227,8 @@
 
 	regs[r_cp] &= ~0x20;
 	regs[r_cp] |= ((force & 1) << 5);
-	tda18271_write_regs(fe, r_cp, 1);
 
-	return 0;
+	return tda18271_write_regs(fe, r_cp, 1);
 }
 
 int tda18271_init_regs(struct dvb_frontend *fe)
@@ -487,16 +486,15 @@
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
 
-	tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+	if (tda18271_debug & DBG_ADV)
+		tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
 
 	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
 	regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
 			sm_lt ? (1 << 6) : 0 |
 			sm_xt ? (1 << 5) : 0;
 
-	tda18271_write_regs(fe, R_EP3, 1);
-
-	return 0;
+	return tda18271_write_regs(fe, R_EP3, 1);
 }
 
 /*---------------------------------------------------------------------*/
@@ -510,7 +508,7 @@
 	u32 div;
 
 	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_MPD]   = (0x77 & pd);
@@ -542,7 +540,7 @@
 	u32 div;
 
 	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_CPD]   = pd;
@@ -566,7 +564,7 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
@@ -583,7 +581,7 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
@@ -600,7 +598,7 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
@@ -617,7 +615,7 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
@@ -634,7 +632,7 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	regs[R_EP5] &= ~0x07;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index b262100..89c01fb 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -51,6 +51,7 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 	u32 N;
 
 	/* update TV broadcast parameters */
@@ -85,7 +86,9 @@
 	/* update rf top / if top */
 	regs[R_EB22]  = 0x00;
 	regs[R_EB22] |= map->rfagc_top;
-	tda18271_write_regs(fe, R_EB22, 1);
+	ret = tda18271_write_regs(fe, R_EB22, 1);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* --------------------------------------------------------------- */
 
@@ -121,7 +124,9 @@
 	/* agc1 has priority on agc2 */
 	regs[R_EB1]  &= ~0x01;
 
-	tda18271_write_regs(fe, R_EB1, 1);
+	ret = tda18271_write_regs(fe, R_EB1, 1);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* --------------------------------------------------------------- */
 
@@ -141,7 +146,9 @@
 		break;
 	}
 
-	tda18271_write_regs(fe, R_TM, 7);
+	ret = tda18271_write_regs(fe, R_TM, 7);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* force charge pump source */
 	charge_pump_source(fe, 1);
@@ -158,9 +165,9 @@
 		regs[R_EP3] &= ~0x04;
 	else
 		regs[R_EP3] |= 0x04;
-	tda18271_write_regs(fe, R_EP3, 1);
-
-	return 0;
+	ret = tda18271_write_regs(fe, R_EP3, 1);
+fail:
+	return ret;
 }
 
 static int tda18271_read_thermometer(struct dvb_frontend *fe)
@@ -213,11 +220,13 @@
 	struct tda18271_priv *priv = fe->tuner_priv;
 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
 	unsigned char *regs = priv->tda18271_regs;
-	int tm_current, rfcal_comp, approx, i;
+	int tm_current, rfcal_comp, approx, i, ret;
 	u8 dc_over_dt, rf_tab;
 
 	/* power up */
-	tda18271_set_standby_mode(fe, 0, 0, 0);
+	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* read die current temperature */
 	tm_current = tda18271_read_thermometer(fe);
@@ -228,8 +237,8 @@
 	rf_tab = regs[R_EB14];
 
 	i = tda18271_lookup_rf_band(fe, &freq, NULL);
-	if (i < 0)
-		return -EINVAL;
+	if (tda_fail(i))
+		return i;
 
 	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
 		approx = map[i].rf_a1 *
@@ -250,35 +259,42 @@
 	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
 
 	regs[R_EB14] = approx + rfcal_comp;
-	tda18271_write_regs(fe, R_EB14, 1);
-
-	return 0;
+	ret = tda18271_write_regs(fe, R_EB14, 1);
+fail:
+	return ret;
 }
 
 static int tda18271_por(struct dvb_frontend *fe)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 
 	/* power up detector 1 */
 	regs[R_EB12] &= ~0x20;
-	tda18271_write_regs(fe, R_EB12, 1);
+	ret = tda18271_write_regs(fe, R_EB12, 1);
+	if (tda_fail(ret))
+		goto fail;
 
 	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
 	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
-	tda18271_write_regs(fe, R_EB18, 1);
+	ret = tda18271_write_regs(fe, R_EB18, 1);
+	if (tda_fail(ret))
+		goto fail;
 
 	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
 
 	/* POR mode */
-	tda18271_set_standby_mode(fe, 1, 0, 0);
+	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* disable 1.5 MHz low pass filter */
 	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
 	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
-	tda18271_write_regs(fe, R_EB21, 3);
-
-	return 0;
+	ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+	return ret;
 }
 
 static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
@@ -389,7 +405,7 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
-	int sgn, bcal, count, wait;
+	int sgn, bcal, count, wait, ret;
 	u8 cid_target;
 	u16 count_limit;
 	u32 freq;
@@ -421,7 +437,9 @@
 	tda18271_write_regs(fe, R_EP2, 1);
 
 	/* read power detection info, stored in EB10 */
-	tda18271_read_extended(fe);
+	ret = tda18271_read_extended(fe);
+	if (tda_fail(ret))
+		return ret;
 
 	/* algorithm initialization */
 	sgn = 1;
@@ -447,7 +465,9 @@
 		tda18271_write_regs(fe, R_EP2, 1);
 
 		/* read power detection info, stored in EB10 */
-		tda18271_read_extended(fe);
+		ret = tda18271_read_extended(fe);
+		if (tda_fail(ret))
+			return ret;
 
 		count += 200;
 
@@ -478,6 +498,7 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 
 	/* set standard to digital */
 	regs[R_EP3]  &= ~0x1f; /* clear std bits */
@@ -489,10 +510,14 @@
 	/* update IF output level & IF notch frequency */
 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
 
-	tda18271_write_regs(fe, R_EP3, 2);
+	ret = tda18271_write_regs(fe, R_EP3, 2);
+	if (tda_fail(ret))
+		goto fail;
 
 	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
-	tda18271_write_regs(fe, R_EB18, 1);
+	ret = tda18271_write_regs(fe, R_EB18, 1);
+	if (tda_fail(ret))
+		goto fail;
 
 	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
 
@@ -500,9 +525,9 @@
 	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
 	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
 
-	tda18271_write_regs(fe, R_EB21, 3);
-
-	return 0;
+	ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+	return ret;
 }
 
 static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
@@ -521,7 +546,7 @@
 
 	i = tda18271_lookup_rf_band(fe, &freq, NULL);
 
-	if (i < 0)
+	if (tda_fail(i))
 		return i;
 
 	rf_default[RF1] = 1000 * map[i].rf1_def;
@@ -535,6 +560,8 @@
 
 		/* look for optimized calibration frequency */
 		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+		if (tda_fail(bcal))
+			return bcal;
 
 		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
 		prog_tab[rf] = regs[R_EB14];
@@ -575,22 +602,29 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned int i;
+	int ret;
 
 	tda_info("tda18271: performing RF tracking filter calibration\n");
 
 	/* wait for die temperature stabilization */
 	msleep(200);
 
-	tda18271_powerscan_init(fe);
+	ret = tda18271_powerscan_init(fe);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* rf band calibration */
-	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
+	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
+		ret =
 		tda18271_rf_tracking_filters_init(fe, 1000 *
 						  priv->rf_cal_state[i].rfmax);
+		if (tda_fail(ret))
+			goto fail;
+	}
 
 	priv->tm_rfcal = tda18271_read_thermometer(fe);
-
-	return 0;
+fail:
+	return ret;
 }
 
 /* ------------------------------------------------------------------ */
@@ -599,6 +633,7 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 
 	/* test RF_CAL_OK to see if we need init */
 	if ((regs[R_EP1] & 0x10) == 0)
@@ -607,15 +642,22 @@
 	if (priv->cal_initialized)
 		return 0;
 
-	tda18271_calc_rf_filter_curve(fe);
+	ret = tda18271_calc_rf_filter_curve(fe);
+	if (tda_fail(ret))
+		goto fail;
 
-	tda18271_por(fe);
+	ret = tda18271_por(fe);
+	if (tda_fail(ret))
+		goto fail;
 
 	tda_info("tda18271: RF tracking filter calibration complete\n");
 
 	priv->cal_initialized = true;
-
-	return 0;
+	goto end;
+fail:
+	tda_info("tda18271: RF tracking filter calibration failed!\n");
+end:
+	return ret;
 }
 
 static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
@@ -623,6 +665,7 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 	u32 N = 0;
 
 	/* calculate bp filter */
@@ -671,7 +714,10 @@
 
 	tda18271_calc_main_pll(fe, N);
 
-	tda18271_write_regs(fe, R_EP3, 11);
+	ret = tda18271_write_regs(fe, R_EP3, 11);
+	if (tda_fail(ret))
+		return ret;
+
 	msleep(5); /* RF tracking filter calibration initialization */
 
 	/* search for K,M,CO for RF calibration */
@@ -719,45 +765,56 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
+	int ret;
 
-	tda18271_read_regs(fe);
+	ret = tda18271_read_regs(fe);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* test IR_CAL_OK to see if we need init */
 	if ((regs[R_EP1] & 0x08) == 0)
-		tda18271_init_regs(fe);
-
-	return 0;
+		ret = tda18271_init_regs(fe);
+fail:
+	return ret;
 }
 
 static int tda18271_init(struct dvb_frontend *fe)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
 
 	mutex_lock(&priv->lock);
 
 	/* power up */
-	tda18271_set_standby_mode(fe, 0, 0, 0);
+	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
 
 	/* initialization */
-	tda18271_ir_cal_init(fe);
+	ret = tda18271_ir_cal_init(fe);
+	if (tda_fail(ret))
+		goto fail;
 
 	if (priv->id == TDA18271HDC2)
 		tda18271c2_rf_cal_init(fe);
-
+fail:
 	mutex_unlock(&priv->lock);
 
-	return 0;
+	return ret;
 }
 
 static int tda18271_tune(struct dvb_frontend *fe,
 			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
 
 	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
 		freq, map->if_freq, bw, map->agc_mode, map->std);
 
-	tda18271_init(fe);
+	ret = tda18271_init(fe);
+	if (tda_fail(ret))
+		goto fail;
 
 	mutex_lock(&priv->lock);
 
@@ -769,11 +826,11 @@
 		tda18271c2_rf_tracking_filters_correction(fe, freq);
 		break;
 	}
-	tda18271_channel_configuration(fe, map, freq, bw);
+	ret = tda18271_channel_configuration(fe, map, freq, bw);
 
 	mutex_unlock(&priv->lock);
-
-	return 0;
+fail:
+	return ret;
 }
 
 /* ------------------------------------------------------------------ */
@@ -837,7 +894,7 @@
 
 	ret = tda18271_tune(fe, map, freq, bw);
 
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	priv->frequency = freq;
@@ -893,7 +950,7 @@
 
 	ret = tda18271_tune(fe, map, freq, 0);
 
-	if (ret < 0)
+	if (tda_fail(ret))
 		goto fail;
 
 	priv->frequency = freq;
@@ -905,16 +962,17 @@
 static int tda18271_sleep(struct dvb_frontend *fe)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
 
 	mutex_lock(&priv->lock);
 
 	/* standby mode w/ slave tuner output
 	 * & loop thru & xtal oscillator on */
-	tda18271_set_standby_mode(fe, 1, 0, 0);
+	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
 
 	mutex_unlock(&priv->lock);
 
-	return 0;
+	return ret;
 }
 
 static int tda18271_release(struct dvb_frontend *fe)
@@ -1095,10 +1153,10 @@
 		if (cfg)
 			priv->small_i2c = cfg->small_i2c;
 
-		if (tda18271_get_id(fe) < 0)
+		if (tda_fail(tda18271_get_id(fe)))
 			goto fail;
 
-		if (tda18271_assign_map_layout(fe) < 0)
+		if (tda_fail(tda18271_assign_map_layout(fe)))
 			goto fail;
 
 		mutex_lock(&priv->lock);
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
index 2bc5eb3..81a7393 100644
--- a/drivers/media/common/tuners/tda18271-priv.h
+++ b/drivers/media/common/tuners/tda18271-priv.h
@@ -153,6 +153,15 @@
 #define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
 #define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
 
+#define tda_fail(ret)							     \
+({									     \
+	int __ret;							     \
+	__ret = (ret < 0);						     \
+	if (__ret)							     \
+		tda_printk(KERN_ERR, "error %d on line %d\n", ret, __LINE__);\
+	__ret;								     \
+})
+
 /*---------------------------------------------------------------------*/
 
 enum tda18271_map_type {
diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c
index f6e7d7a..1f56463 100644
--- a/drivers/media/common/tuners/tea5767.c
+++ b/drivers/media/common/tuners/tea5767.c
@@ -373,14 +373,14 @@
 
 	if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
 		printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
-		return EINVAL;
+		return -EINVAL;
 	}
 
 	/* If all bytes are the same then it's a TV tuner and not a tea5767 */
 	if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
 	    buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
 		printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
-		return EINVAL;
+		return -EINVAL;
 	}
 
 	/*  Status bytes:
@@ -390,7 +390,7 @@
 	 */
 	if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
 		printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
-		return EINVAL;
+		return -EINVAL;
 	}
 
 
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 43d35bd..ceae6db 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -212,7 +212,7 @@
 	dprintk(1, "%s()\n", __func__);
 
 	if (priv->cfg->tuner_callback) {
-		ret = priv->cfg->tuner_callback(priv->cfg->priv,
+		ret = priv->cfg->tuner_callback(priv->devptr,
 						XC5000_TUNER_RESET, 0);
 		if (ret)
 			printk(KERN_ERR "xc5000: reset failed\n");
@@ -900,9 +900,9 @@
 	.get_status	   = xc5000_get_status
 };
 
-struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c,
-	struct xc5000_config *cfg)
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   struct xc5000_config *cfg, void *devptr)
 {
 	struct xc5000_priv *priv = NULL;
 	u16 id = 0;
@@ -916,6 +916,7 @@
 	priv->cfg = cfg;
 	priv->bandwidth = BANDWIDTH_6_MHZ;
 	priv->i2c = i2c;
+	priv->devptr = devptr;
 
 	/* Check if firmware has been loaded. It is possible that another
 	   instance of the driver has loaded the firmware.
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index 0ee80f9..c910715 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -31,29 +31,31 @@
 	u8   i2c_address;
 	u32  if_khz;
 
-	/* For each bridge framework, when it attaches either analog or digital,
-	 * it has to store a reference back to its _core equivalent structure,
-	 * so that it can service the hardware by steering gpio's etc.
-	 * Each bridge implementation is different so cast priv accordingly.
-	 * The xc5000 driver cares not for this value, other than ensuring
-	 * it's passed back to a bridge during tuner_callback().
-	 */
-	void *priv;
 	int  (*tuner_callback) (void *priv, int command, int arg);
 };
 
 /* xc5000 callback command */
 #define XC5000_TUNER_RESET		0
 
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc5000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
 #if defined(CONFIG_MEDIA_TUNER_XC5000) || \
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
 					  struct i2c_adapter *i2c,
-					  struct xc5000_config *cfg);
+					  struct xc5000_config *cfg,
+					  void *devptr);
 #else
 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
 						 struct i2c_adapter *i2c,
-						 struct xc5000_config *cfg)
+						 struct xc5000_config *cfg,
+						 void *devptr)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index 13b2d19..ecebfe4 100644
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -31,6 +31,8 @@
 	u8  video_standard;
 	u8  rf_mode;
 	u8  fwloaded;
+
+	void *devptr;
 };
 
 #endif
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 7b0ea3b..f9d0876 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -634,7 +634,7 @@
 	}
 
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
-	fc->fe = dvb_attach(vp310_mt312_attach,
+	fc->fe = dvb_attach(mt312_attach,
 		&skystar23_samsung_tbdu18132_config, i2c);
 	if (fc->fe != NULL) {
 		ops = &fc->fe->ops;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index d1239b8..7588db1 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,6 +1,7 @@
 config DVB_BT8XX
 	tristate "BT8xx based PCI cards"
 	depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+	depends on HOTPLUG	# due to FW_LOADER
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_SP887X if !DVB_FE_CUSTOMISE
 	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 3d778c5..c03513b 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -1,6 +1,6 @@
 config DVB_CINERGYT2
 	tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
-	depends on DVB_CORE && USB
+	depends on DVB_CORE && USB && INPUT
 	help
 	  Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 8cbdb0e..588fbe1 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -910,15 +910,21 @@
 	int curdelay = 100000000;
 	int slot;
 
+	/* Beware of too high polling frequency, because one polling
+	 * call might take several hundred milliseconds until timeout!
+	 */
 	for (slot = 0; slot < ca->slot_count; slot++) {
 		switch (ca->slot_info[slot].slot_state) {
 		default:
 		case DVB_CA_SLOTSTATE_NONE:
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ * 5;  /* 5s */
+			break;
 		case DVB_CA_SLOTSTATE_INVALID:
-			delay = HZ * 60;
-			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-				delay = HZ / 10;
-			}
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ / 10;  /* 100ms */
 			break;
 
 		case DVB_CA_SLOTSTATE_UNINITIALISED:
@@ -926,19 +932,17 @@
 		case DVB_CA_SLOTSTATE_VALIDATE:
 		case DVB_CA_SLOTSTATE_WAITFR:
 		case DVB_CA_SLOTSTATE_LINKINIT:
-			delay = HZ / 10;
+			delay = HZ / 10;  /* 100ms */
 			break;
 
 		case DVB_CA_SLOTSTATE_RUNNING:
-			delay = HZ * 60;
-			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-				delay = HZ / 10;
-			}
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ / 10;  /* 100ms */
 			if (ca->open) {
 				if ((!ca->slot_info[slot].da_irq_supported) ||
-				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
-					delay = HZ / 10;
-				}
+				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+					delay = HZ / 10;  /* 100ms */
 			}
 			break;
 		}
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 4c1cff9..cf4584e 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,7 @@
 config DVB_USB
 	tristate "Support for various USB DVB devices"
 	depends on DVB_CORE && USB && I2C
+	depends on HOTPLUG	# due to FW_LOADER
 	select FW_LOADER
 	help
 	  By enabling this you will be able to choose the various supported
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 6d23846..c20553c 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -30,7 +30,7 @@
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 config DVB_MT312
-	tristate "Zarlink VP310/MT312 based"
+	tristate "Zarlink VP310/MT312/ZL10313 based"
 	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
@@ -97,7 +97,7 @@
 
 config DVB_SP8870
 	tristate "Spase sp8870 based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -110,7 +110,7 @@
 
 config DVB_SP887X
 	tristate "Spase sp887x based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -144,7 +144,7 @@
 
 config DVB_TDA1004X
 	tristate "Philips TDA10045H/TDA10046H based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -211,7 +211,7 @@
 
 config DVB_TDA10048
 	tristate "Philips TDA10048HN based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -253,7 +253,7 @@
 
 config DVB_NXT200X
 	tristate "NxtWave Communications NXT2002/NXT2004 based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -268,7 +268,7 @@
 
 config DVB_OR51211
 	tristate "Oren OR51211 based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -281,7 +281,7 @@
 
 config DVB_OR51132
 	tristate "Oren OR51132 based"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -297,7 +297,7 @@
 
 config DVB_BCM3510
 	tristate "Broadcom BCM3510"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && HOTPLUG
 	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c
index 04c562c..600dad6 100644
--- a/drivers/media/dvb/frontends/itd1000.c
+++ b/drivers/media/dvb/frontends/itd1000.c
@@ -195,7 +195,7 @@
 	}
 }
 
-struct {
+static const struct {
 	u32 freq;
 	u8 values[10]; /* RFTR, RFST1 - RFST9 */
 } itd1000_fre_values[] = {
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 081ca33..5ac9b15 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -737,7 +737,7 @@
 }
 
 #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
-static struct dvb_frontend_ops vp310_mt312_ops = {
+static struct dvb_frontend_ops mt312_ops = {
 
 	.info = {
 		.name = "Zarlink ???? DVB-S",
@@ -776,7 +776,7 @@
 	.set_voltage = mt312_set_voltage,
 };
 
-struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
 					struct i2c_adapter *i2c)
 {
 	struct mt312_state *state = NULL;
@@ -795,7 +795,7 @@
 		goto error;
 
 	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &vp310_mt312_ops,
+	memcpy(&state->frontend.ops, &mt312_ops,
 		sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
@@ -827,12 +827,13 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(vp310_mt312_attach);
+EXPORT_SYMBOL(mt312_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index de796ea..29e3bb5 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -37,10 +37,10 @@
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
 					struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend *vp310_mt312_attach(
+static inline struct dvb_frontend *mt312_attach(
 	const struct mt312_config *config, struct i2c_adapter *i2c)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index ae882432..d4339b1 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -5,6 +5,7 @@
 config DVB_AV7110
 	tristate "AV7110 cards"
 	depends on DVB_CORE && PCI && I2C
+	depends on HOTPLUG
 	select FW_LOADER if !DVB_AV7110_FIRMWARE
 	select TTPCI_EEPROM
 	select VIDEO_SAA7146_VV
@@ -123,6 +124,7 @@
 	depends on DVB_BUDGET_CORE && I2C
 	select VIDEO_SAA7146_VV
 	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
+	depends on HOTPLUG	# dependency of FW_LOADER
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index 8361101..0712899 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,6 +1,7 @@
 config DVB_TTUSB_DEC
 	tristate "Technotrend/Hauppauge USB DEC devices"
 	depends on DVB_CORE && USB
+	depends on HOTPLUG	# due to FW_LOADER
 	select FW_LOADER
 	select CRC32
 	help
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fe743aa..89d8d37 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -44,6 +44,10 @@
 	tristate
 	depends on I2C
 
+config VIDEO_TUNER
+	tristate
+	depends on MEDIA_TUNER
+
 #
 # Multimedia Video device configuration
 #
@@ -690,7 +694,7 @@
 	tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
 	depends on PCI && VIDEO_V4L1 && I2C
 	select VIDEO_SAA7146_VV
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
@@ -906,7 +910,7 @@
 
 config SOC_CAMERA_MT9M001
 	tristate "mt9m001 support"
-	depends on SOC_CAMERA
+	depends on SOC_CAMERA && I2C
 	select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
 	help
 	  This driver supports MT9M001 cameras from Micron, monochrome
@@ -921,7 +925,7 @@
 
 config SOC_CAMERA_MT9V022
 	tristate "mt9v022 support"
-	depends on SOC_CAMERA
+	depends on SOC_CAMERA && I2C
 	select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
 	help
 	  This driver supports MT9V022 cameras from Micron
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a352c6e..dff0d6a 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -84,7 +84,7 @@
 obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
-obj-$(CONFIG_MEDIA_TUNER) += tuner.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index cab277f..def10d0 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -1,8 +1,9 @@
 
 config VIDEO_AU0828
 	tristate "Auvitek AU0828 support"
-       depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
+	depends on VIDEO_DEV && I2C && INPUT && DVB_CORE && USB
 	select I2C_ALGOBIT
+	select VIDEO_TVEEPROM
 	select DVB_AU8522 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
 	---help---
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 1371b4e..c86a5f1 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -337,12 +337,10 @@
 		dvb->frontend = dvb_attach(au8522_attach,
 				&hauppauge_hvr950q_config,
 				&dev->i2c_adap);
-		if (dvb->frontend != NULL) {
-			hauppauge_hvr950q_tunerconfig.priv = dev;
+		if (dvb->frontend != NULL)
 			dvb_attach(xc5000_attach, dvb->frontend,
 				&dev->i2c_adap,
-				&hauppauge_hvr950q_tunerconfig);
-		}
+				&hauppauge_hvr950q_tunerconfig, dev);
 		break;
 	default:
 		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 7431ef6..24a34fc 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,12 +1,13 @@
 config VIDEO_BT848
 	tristate "BT848 Video For Linux"
 	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+	depends on HOTPLUG	# due to FW_LOADER
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
 	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index acc4b47..5f94269 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -1,14 +1,17 @@
 config VIDEO_CX18
 	tristate "Conexant cx23418 MPEG encoder support"
 	depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+	depends on INPUT	# due to VIDEO_IR
+	depends on HOTPLUG	# due to FW_LOADER
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_IR
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
 	select VIDEO_CS5345
 	select DVB_S5H1409
+	select MEDIA_TUNER_MXL5005S
 	---help---
 	  This is a video4linux driver for Conexant cx23418 based
 	  PCI combo video recorder devices.
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index f5e3ba1..553adbf 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -47,11 +47,12 @@
 static const struct cx18_card cx18_card_hvr1600_esmt = {
 	.type = CX18_CARD_HVR_1600_ESMT,
 	.name = "Hauppauge HVR-1600",
-	.comment = "DVB & VBI are not yet supported\n",
+	.comment = "VBI is not yet supported\n",
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_muxer = CX18_HW_CS5345,
-	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+		  CX18_HW_CS5345 | CX18_HW_DVB,
 	.video_inputs = {
 		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
 		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
@@ -86,11 +87,12 @@
 static const struct cx18_card cx18_card_hvr1600_samsung = {
 	.type = CX18_CARD_HVR_1600_SAMSUNG,
 	.name = "Hauppauge HVR-1600 (Preproduction)",
-	.comment = "DVB & VBI are not yet supported\n",
+	.comment = "VBI is not yet supported\n",
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_muxer = CX18_HW_CS5345,
-	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+		  CX18_HW_CS5345 | CX18_HW_DVB,
 	.video_inputs = {
 		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
 		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
@@ -134,14 +136,15 @@
 static const struct cx18_card cx18_card_h900 = {
 	.type = CX18_CARD_COMPRO_H900,
 	.name = "Compro VideoMate H900",
-	.comment = "Not yet supported!\n",
-	.v4l2_capabilities = 0,
+	.comment = "DVB & VBI are not yet supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_all = CX18_HW_TUNER,
 	.video_inputs = {
-		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
-		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
-		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX23418_SVIDEO_LUMA3 | CX23418_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE1 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
@@ -163,6 +166,7 @@
 		.tune_lane = 0,
 		.initial_emrs = 0,
 	},
+	.xceive_pin = 15,
 	.pci_list = cx18_pci_h900,
 	.i2c = &cx18_i2c_std,
 };
@@ -200,8 +204,6 @@
 		/* XC3028 tuner */
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
-	/* tuner reset */
-	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 },
 	.ddr = {
 		/* Probably Samsung K4D263238G-VC33 memory */
 		.chip_config = 0x003,
@@ -211,6 +213,7 @@
 		.tune_lane = 0,
 		.initial_emrs = 2,
 	},
+	.xceive_pin = 15,
 	.pci_list = cx18_pci_mpc718,
 	.i2c = &cx18_i2c_std,
 };
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index bca249b..bccb67f 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -114,8 +114,8 @@
 /* The mask is the set of bits used by the operation */
 
 struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
-	u16 direction; 	/* DIR setting. Leave to 0 if no init is needed */
-	u16 initial_value;
+	u32 direction; 	/* DIR setting. Leave to 0 if no init is needed */
+	u32 initial_value;
 };
 
 struct cx18_card_tuner {
@@ -153,6 +153,7 @@
 	struct cx18_card_audio_input radio_input;
 
 	/* GPIO card-specific settings */
+	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
 	struct cx18_gpio_init 		gpio_init;
 
 	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 3f55d47..0dd4e05 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -164,16 +164,6 @@
 
 MODULE_VERSION(CX18_VERSION);
 
-int cx18_waitq(wait_queue_head_t *waitq)
-{
-	DEFINE_WAIT(wait);
-
-	prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE);
-	schedule();
-	finish_wait(waitq, &wait);
-	return signal_pending(current) ? -EINTR : 0;
-}
-
 /* Generic utility functions */
 int cx18_msleep_timeout(unsigned int msecs, int intr)
 {
@@ -220,13 +210,13 @@
 
 	/* Many thanks to Steven Toth from Hauppauge for providing the
 	   model numbers */
+	/* Note: the Samsung memory models cannot be reliably determined
+	   from the model number. Use the cardtype module option if you
+	   have one of these preproduction models. */
 	switch (tv.model) {
-	case 74000 ... 74099:
+	case 74000 ... 74999:
 		cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
 		break;
-	case 74700 ... 74799:
-		cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG);
-		break;
 	case 0:
 		CX18_ERR("Invalid EEPROM\n");
 		return;
@@ -548,6 +538,7 @@
 	return 0;
 }
 
+#ifdef MODULE
 static u32 cx18_request_module(struct cx18 *cx, u32 hw,
 		const char *name, u32 id)
 {
@@ -560,12 +551,14 @@
 	CX18_DEBUG_INFO("Loaded module %s\n", name);
 	return hw;
 }
+#endif
 
 static void cx18_load_and_init_modules(struct cx18 *cx)
 {
 	u32 hw = cx->card->hw_all;
 	int i;
 
+#ifdef MODULE
 	/* load modules */
 #ifndef CONFIG_MEDIA_TUNER
 	hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
@@ -573,6 +566,7 @@
 #ifndef CONFIG_VIDEO_CS5345
 	hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
 #endif
+#endif
 
 	/* check which i2c devices are actually found */
 	for (i = 0; i < 32; i++) {
@@ -801,7 +795,7 @@
 	return 0;
 
 free_streams:
-	cx18_streams_cleanup(cx);
+	cx18_streams_cleanup(cx, 1);
 free_irq:
 	free_irq(cx->dev->irq, (void *)cx);
 free_i2c:
@@ -904,14 +898,13 @@
 
 	cx18_halt_firmware(cx);
 
-	cx18_streams_cleanup(cx);
+	cx18_streams_cleanup(cx, 1);
 
 	exit_cx18_i2c(cx);
 
 	free_irq(cx->dev->irq, (void *)cx);
 
-	if (cx->dev)
-		cx18_iounmap(cx);
+	cx18_iounmap(cx);
 
 	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
 
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 2ee9391..a2a6c58 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -444,9 +444,6 @@
 /* Return non-zero if a signal is pending */
 int cx18_msleep_timeout(unsigned int msecs, int intr);
 
-/* Wait on queue, returns -EINTR if interrupted */
-int cx18_waitq(wait_queue_head_t *waitq);
-
 /* Read Hauppauge eeprom */
 struct tveeprom; /* forward reference */
 void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 65efe69..c974417 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -24,25 +24,27 @@
 #include "cx18-streams.h"
 #include "cx18-cards.h"
 #include "s5h1409.h"
-
-/* Wait until the MXL500X driver is merged */
-#ifdef HAVE_MXL500X
-#include "mxl500x.h"
-#endif
+#include "mxl5005s.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
 
-#ifdef HAVE_MXL500X
-static struct mxl500x_config hauppauge_hvr1600_tuner = {
-	.delsys    = MXL500x_MODE_ATSC,
-	.octf      = MXL500x_OCTF_CH,
-	.xtal_freq = 16000000,
-	.iflo_freq = 5380000,
-	.ref_freq  = 322800000,
-	.rssi_ena  = MXL_RSSI_ENABLE,
-	.addr      = 0xC6 >> 1,
+static struct mxl5005s_config hauppauge_hvr1600_tuner = {
+	.i2c_address     = 0xC6 >> 1,
+	.if_freq         = IF_FREQ_5380000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C_H,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
 };
 
 static struct s5h1409_config hauppauge_hvr1600_config = {
@@ -55,7 +57,6 @@
 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 
 };
-#endif
 
 static int dvb_register(struct cx18_stream *stream);
 
@@ -252,21 +253,18 @@
 	int ret = 0;
 
 	switch (cx->card->type) {
-/* Wait until the MXL500X driver is merged */
-#ifdef HAVE_MXL500X
 	case CX18_CARD_HVR_1600_ESMT:
 	case CX18_CARD_HVR_1600_SAMSUNG:
 		dvb->fe = dvb_attach(s5h1409_attach,
 			&hauppauge_hvr1600_config,
 			&cx->i2c_adap[0]);
 		if (dvb->fe != NULL) {
-			dvb_attach(mxl500x_attach, dvb->fe,
-				&hauppauge_hvr1600_tuner,
-				&cx->i2c_adap[0]);
+			dvb_attach(mxl5005s_attach, dvb->fe,
+				&cx->i2c_adap[0],
+				&hauppauge_hvr1600_tuner);
 			ret = 0;
 		}
 		break;
-#endif
 	default:
 		/* No Digital Tv Support */
 		break;
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 6930306..0b3141d 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -39,7 +39,7 @@
    associated VBI streams are also automatically claimed.
    Possible error returns: -EBUSY if someone else has claimed
    the stream or 0 on success. */
-int cx18_claim_stream(struct cx18_open_id *id, int type)
+static int cx18_claim_stream(struct cx18_open_id *id, int type)
 {
 	struct cx18 *cx = id->cx;
 	struct cx18_stream *s = &cx->streams[type];
@@ -87,7 +87,7 @@
 
 /* This function releases a previously claimed stream. It will take into
    account associated VBI streams. */
-void cx18_release_stream(struct cx18_stream *s)
+static void cx18_release_stream(struct cx18_stream *s)
 {
 	struct cx18 *cx = s->cx;
 	struct cx18_stream *s_vbi;
@@ -662,6 +662,8 @@
 	for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
 		/* find out which stream this open was on */
 		for (y = 0; y < CX18_MAX_STREAMS; y++) {
+			if (cx18_cards[x] == NULL)
+				continue;
 			s = &cx18_cards[x]->streams[y];
 			if (s->v4l2dev && s->v4l2dev->minor == minor) {
 				cx = cx18_cards[x];
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
index 16cdafb..46da028 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -34,12 +34,3 @@
 void cx18_mute(struct cx18 *cx);
 void cx18_unmute(struct cx18 *cx);
 
-/* Utilities */
-
-/* Try to claim a stream for the filehandle. Return 0 on success,
-   -EBUSY if stream already claimed. Once a stream is claimed, it
-   remains claimed until the associated filehandle is closed. */
-int cx18_claim_stream(struct cx18_open_id *id, int type);
-
-/* Release a previously claimed stream. */
-void cx18_release_stream(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 19253e6..bb8bc86 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -35,6 +35,9 @@
 #define CX18_REG_GPIO_OUT2   0xc78104
 #define CX18_REG_GPIO_DIR2   0xc7810c
 
+static u32 gpio_dir;
+static u32 gpio_val;
+
 /*
  * HVR-1600 GPIO pins, courtesy of Hauppauge:
  *
@@ -44,31 +47,53 @@
  * gpio13: cs5345 reset pin
 */
 
+static void gpio_write(struct cx18 *cx)
+{
+	write_reg((gpio_dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+	write_reg(((gpio_dir & 0xffff) << 16) | (gpio_val & 0xffff),
+			CX18_REG_GPIO_OUT1);
+	write_reg(gpio_dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+	write_reg((gpio_dir & 0xffff0000) | ((gpio_val & 0xffff0000) >> 16),
+			CX18_REG_GPIO_OUT2);
+}
+
 void cx18_gpio_init(struct cx18 *cx)
 {
-	if (cx->card->gpio_init.direction == 0)
+	gpio_dir = cx->card->gpio_init.direction;
+	gpio_val = cx->card->gpio_init.initial_value;
+
+	if (gpio_dir == 0)
 		return;
 
-	CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
-		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1));
+	gpio_dir |= 1 << cx->card->xceive_pin;
+	gpio_val |= 1 << cx->card->xceive_pin;
 
-	/* init output data then direction */
-	write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1);
-	write_reg(0, CX18_REG_GPIO_DIR2);
-	write_reg((cx->card->gpio_init.direction << 16) |
-			cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1);
-	write_reg(0, CX18_REG_GPIO_OUT2);
+	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
+		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
+		   read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+
+	gpio_write(cx);
 }
 
 /* Xceive tuner reset function */
 int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
 {
 	struct i2c_algo_bit_data *algo = dev;
-	struct cx18 *cx = algo->data;
-/*	int curdir, curout;*/
+	struct cx18_i2c_algo_callback_data *cb_data = algo->data;
+	struct cx18 *cx = cb_data->cx;
 
 	if (cmd != XC2028_TUNER_RESET)
 		return 0;
 	CX18_DEBUG_INFO("Resetting tuner\n");
+
+	gpio_dir |= 1 << cx->card->xceive_pin;
+	gpio_val &= ~(1 << cx->card->xceive_pin);
+
+	gpio_write(cx);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+	gpio_val |= 1 << cx->card->xceive_pin;
+	gpio_write(cx);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	return 0;
 }
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 18c88d1..4f08a40 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -25,6 +25,7 @@
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "cx18-av-core.h"
+#include "cx18-i2c.h"
 
 #include <media/ir-kbd-i2c.h>
 
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 65af1bb..6990b77 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -26,17 +26,6 @@
 #include "cx18-queue.h"
 #include "cx18-scb.h"
 
-int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
-		const char __user *src, int copybytes)
-{
-	if (s->buf_size - buf->bytesused < copybytes)
-		copybytes = s->buf_size - buf->bytesused;
-	if (copy_from_user(buf->buf + buf->bytesused, src, copybytes))
-		return -EFAULT;
-	buf->bytesused += copybytes;
-	return copybytes;
-}
-
 void cx18_buf_swap(struct cx18_buffer *buf)
 {
 	int i;
@@ -159,8 +148,9 @@
    -ENOMEM is returned if the buffers could not be obtained, 0 if all
    buffers where obtained from the 'from' list and if non-zero then
    the number of stolen buffers is returned. */
-int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
-	struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes)
+static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
+			   struct cx18_queue *steal, struct cx18_queue *to,
+			   int needed_bytes)
 {
 	unsigned long flags;
 	int rc = 0;
@@ -239,12 +229,12 @@
 
 	/* allocate stream buffers. Initially all buffers are in q_free. */
 	for (i = 0; i < s->buffers; i++) {
-		struct cx18_buffer *buf =
-			kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL);
+		struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer),
+						GFP_KERNEL|__GFP_NOWARN);
 
 		if (buf == NULL)
 			break;
-		buf->buf = kmalloc(s->buf_size, GFP_KERNEL);
+		buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN);
 		if (buf->buf == NULL) {
 			kfree(buf);
 			break;
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index f86c8a6..91423b9 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -39,8 +39,6 @@
 				s->buf_size, s->dma);
 }
 
-int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
-	const char __user *src, int copybytes);
 void cx18_buf_swap(struct cx18_buffer *buf);
 
 /* cx18_queue utility functions */
@@ -48,8 +46,6 @@
 void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
 	struct cx18_queue *q);
 struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
-       struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes);
 struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
 	u32 bytesused);
 void cx18_flush_queues(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index afb141b..4ca9d84 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -218,7 +218,7 @@
 		return 0;
 
 	/* One or more streams could not be initialized. Clean 'em all up. */
-	cx18_streams_cleanup(cx);
+	cx18_streams_cleanup(cx, 0);
 	return -ENOMEM;
 }
 
@@ -296,12 +296,12 @@
 		return 0;
 
 	/* One or more streams could not be initialized. Clean 'em all up. */
-	cx18_streams_cleanup(cx);
+	cx18_streams_cleanup(cx, 1);
 	return -ENOMEM;
 }
 
 /* Unregister v4l2 devices */
-void cx18_streams_cleanup(struct cx18 *cx)
+void cx18_streams_cleanup(struct cx18 *cx, int unregister)
 {
 	struct video_device *vdev;
 	int type;
@@ -319,8 +319,11 @@
 
 		cx18_stream_free(&cx->streams[type]);
 
-		/* Unregister device */
-		video_unregister_device(vdev);
+		/* Unregister or release device */
+		if (unregister)
+			video_unregister_device(vdev);
+		else
+			video_device_release(vdev);
 	}
 }
 
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 8c7ba7d..f327e94 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -24,7 +24,7 @@
 u32 cx18_find_handle(struct cx18 *cx);
 int cx18_streams_setup(struct cx18 *cx);
 int cx18_streams_register(struct cx18 *cx);
-void cx18_streams_cleanup(struct cx18 *cx);
+void cx18_streams_cleanup(struct cx18 *cx, int unregister);
 
 /* Capture related */
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index cadf936..7bf14c9 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -1,18 +1,20 @@
 config VIDEO_CX23885
 	tristate "Conexant cx23885 (2388x successor) support"
 	depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+	depends on HOTPLUG	# due to FW_LOADER
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
 	select VIDEOBUF_DVB
 	select VIDEO_CX25840
+	select VIDEO_CX2341X
+	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 6ebf587..20e05f2 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -200,6 +200,10 @@
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1200,
 	}, {
 		.subvendor = 0x0070,
+		.subdevice = 0x71d3,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1200,
+	}, {
+		.subvendor = 0x0070,
 		.subdevice = 0x8101,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1700,
 	}, {
@@ -245,6 +249,33 @@
 	/* Make sure we support the board model */
 	switch (tv.model)
 	{
+	case 71009:
+		/* WinTV-HVR1200 (PCIe, Retail, full height)
+		 * DVB-T and basic analog */
+	case 71359:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71439:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71449:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71939:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71949:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71959:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71979:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71999:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
 	case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
 	case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
 	case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
@@ -263,8 +294,11 @@
 	case 80019:
 		/* WinTV-HVR1400 (Express Card, Retail, IR,
 		 * DVB-T and Basic analog */
+	case 81509:
+		/* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
+		 * DVB-T and MPEG2 HW Encoder */
 	case 81519:
-		/* WinTV-HVR1700 (PCIe, Retail, No IR, half height,
+		/* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
 		 * DVB-T and MPEG2 HW Encoder */
 		break;
 	default:
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index f056497..022aa39 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -37,7 +37,6 @@
 #include "lgdt330x.h"
 #include "xc5000.h"
 #include "tda10048.h"
-#include "dvb-pll.h"
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "dib7000p.h"
@@ -385,12 +384,10 @@
 		port->dvb.frontend = dvb_attach(s5h1409_attach,
 						&hauppauge_hvr1500q_config,
 						&dev->i2c_bus[0].i2c_adap);
-		if (port->dvb.frontend != NULL) {
-			hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+		if (port->dvb.frontend != NULL)
 			dvb_attach(xc5000_attach, port->dvb.frontend,
 				&i2c_bus->i2c_adap,
-				&hauppauge_hvr1500q_tunerconfig);
-		}
+				&hauppauge_hvr1500q_tunerconfig, i2c_bus);
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 		i2c_bus = &dev->i2c_bus[1];
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
index 7cf29a0..448f4cd 100644
--- a/drivers/media/video/cx25840/Kconfig
+++ b/drivers/media/video/cx25840/Kconfig
@@ -1,6 +1,7 @@
 config VIDEO_CX25840
 	tristate "Conexant CX2584x audio/video decoders"
 	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on HOTPLUG # due to FW_LOADER
 	select FW_LOADER
 	---help---
 	  Support for the Conexant CX2584x audio/video decoders.
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index b0d7d6a..10e20d8 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -2,10 +2,9 @@
 	tristate "Conexant 2388x (bt878 successor) support"
 	depends on VIDEO_DEV && PCI && I2C && INPUT
 	select I2C_ALGOBIT
-	select FW_LOADER
 	select VIDEO_BTCX
 	select VIDEOBUF_DMA_SG
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
 	select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
@@ -34,8 +33,9 @@
 
 config VIDEO_CX88_BLACKBIRD
 	tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
-	depends on VIDEO_CX88
+	depends on VIDEO_CX88 && HOTPLUG
 	select VIDEO_CX2341X
+	select FW_LOADER
 	---help---
 	  This adds support for MPEG encoder cards based on the
 	  Blackbird reference design, using the Conexant 2388x
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 1c7fe68..d96173f 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -509,9 +509,6 @@
 	if (!fe) {
 		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
 		       dev->core->name);
-		dvb_frontend_detach(dev->dvb.frontend);
-		dvb_unregister_frontend(dev->dvb.frontend);
-		dev->dvb.frontend = NULL;
 		return -EINVAL;
 	}
 
@@ -523,20 +520,23 @@
 
 static int dvb_register(struct cx8802_dev *dev)
 {
+	struct cx88_core *core = dev->core;
+
 	/* init struct videobuf_dvb */
-	dev->dvb.name = dev->core->name;
+	dev->dvb.name = core->name;
 	dev->ts_gen_cntrl = 0x0c;
 
 	/* init frontend */
-	switch (dev->core->boardnr) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
 		dev->dvb.frontend = dvb_attach(cx22702_attach,
 					       &connexant_refboard_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_THOMSON_DTT759X);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x61, &core->i2c_adap,
+					DVB_PLL_THOMSON_DTT759X))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -545,11 +545,12 @@
 	case CX88_BOARD_WINFAST_DTV1000:
 		dev->dvb.frontend = dvb_attach(cx22702_attach,
 					       &connexant_refboard_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_THOMSON_DTT7579);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x60, &core->i2c_adap,
+					DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_WINFAST_DTV2000H:
@@ -559,29 +560,32 @@
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
 		dev->dvb.frontend = dvb_attach(cx22702_attach,
 					       &hauppauge_hvr_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_PHILIPS_FMD1216ME_MK3);
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
 		dev->dvb.frontend = dvb_attach(mt352_attach,
 					       &dvico_fusionhdtv,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				   NULL, DVB_PLL_THOMSON_DTT7579);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
 			break;
 		}
 		/* ZL10353 replaces MT352 on later cards */
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &dvico_fusionhdtv_plus_v1_1,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				   NULL, DVB_PLL_THOMSON_DTT7579);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -589,28 +593,31 @@
 		 * compatible, with a slightly different MT352 AGC gain. */
 		dev->dvb.frontend = dvb_attach(mt352_attach,
 					       &dvico_fusionhdtv_dual,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_THOMSON_DTT7579);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
 			break;
 		}
 		/* ZL10353 replaces MT352 on later cards */
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &dvico_fusionhdtv_plus_v1_1,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_THOMSON_DTT7579);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 		dev->dvb.frontend = dvb_attach(mt352_attach,
 					       &dvico_fusionhdtv,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_LG_Z201);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x61, NULL, DVB_PLL_LG_Z201))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
@@ -618,10 +625,11 @@
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
 		dev->dvb.frontend = dvb_attach(mt352_attach,
 					       &dntv_live_dvbt_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_UNKNOWN_1);
+			if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+					0x61, NULL, DVB_PLL_UNKNOWN_1))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
@@ -630,32 +638,35 @@
 		dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
 					       &dev->vp3054->adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_PHILIPS_FMD1216ME_MK3);
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
 		}
 #else
-		printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
+		printk(KERN_ERR "%s/2: built without vp3054 support\n",
+				core->name);
 #endif
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &dvico_fusionhdtv_hybrid,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_THOMSON_FE6600);
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &core->i2c_adap, 0x61,
+				   TUNER_THOMSON_FE6600))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &dvico_fusionhdtv_xc3028,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend == NULL)
 			dev->dvb.frontend = dvb_attach(mt352_attach,
 						&dvico_fusionhdtv_mt352_xc3028,
-						&dev->core->i2c_adap);
+						&core->i2c_adap);
 		/*
 		 * On this board, the demod provides the I2C bus pullup.
 		 * We must not permit gate_ctrl to be performed, or
@@ -668,19 +679,18 @@
 		break;
 	case CX88_BOARD_PCHDTV_HD3000:
 		dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_THOMSON_DTT761X);
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_THOMSON_DTT761X))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
 		dev->ts_gen_cntrl = 0x08;
-		{
-		/* Do a hardware reset of chip before using it. */
-		struct cx88_core *core = dev->core;
 
+		/* Do a hardware reset of chip before using it. */
 		cx_clear(MO_GP0_IO, 1);
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
@@ -690,139 +700,137 @@
 		fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
 		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
 					       &fusionhdtv_3_gold,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_MICROTUNE_4042FI5);
-		}
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_MICROTUNE_4042FI5))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
 		dev->ts_gen_cntrl = 0x08;
-		{
-		/* Do a hardware reset of chip before using it. */
-		struct cx88_core *core = dev->core;
 
+		/* Do a hardware reset of chip before using it. */
 		cx_clear(MO_GP0_IO, 1);
 		mdelay(100);
 		cx_set(MO_GP0_IO, 9);
 		mdelay(200);
 		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
 					       &fusionhdtv_3_gold,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_THOMSON_DTT761X);
-		}
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_THOMSON_DTT761X))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
 		dev->ts_gen_cntrl = 0x08;
-		{
-		/* Do a hardware reset of chip before using it. */
-		struct cx88_core *core = dev->core;
 
+		/* Do a hardware reset of chip before using it. */
 		cx_clear(MO_GP0_IO, 1);
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
 		mdelay(200);
 		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
 					       &fusionhdtv_5_gold,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_LG_TDVS_H06XF);
-			dvb_attach(tda9887_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x43);
-		}
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_LG_TDVS_H06XF))
+				goto frontend_detach;
+			if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+				   &core->i2c_adap, 0x43))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_PCHDTV_HD5500:
 		dev->ts_gen_cntrl = 0x08;
-		{
-		/* Do a hardware reset of chip before using it. */
-		struct cx88_core *core = dev->core;
 
+		/* Do a hardware reset of chip before using it. */
 		cx_clear(MO_GP0_IO, 1);
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
 		mdelay(200);
 		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
 					       &pchdtv_hd5500,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_LG_TDVS_H06XF);
-			dvb_attach(tda9887_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x43);
-		}
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_LG_TDVS_H06XF))
+				goto frontend_detach;
+			if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+				   &core->i2c_adap, 0x43))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_ATI_HDTVWONDER:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach,
 					       &ati_hdtvwonder,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x61,
-				   TUNER_PHILIPS_TUV1236D);
+			if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_PHILIPS_TUV1236D))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 		dev->dvb.frontend = dvb_attach(cx24123_attach,
 					       &hauppauge_novas_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_attach(isl6421_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap, 0x08, 0x00, 0x00);
+			if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+					&core->i2c_adap, 0x08, 0x00, 0x00))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_KWORLD_DVBS_100:
 		dev->dvb.frontend = dvb_attach(cx24123_attach,
 					       &kworld_dvbs_100_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
 			dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
 		}
 		break;
 	case CX88_BOARD_GENIATECH_DVBS:
 		dev->dvb.frontend = dvb_attach(cx24123_attach,
 					       &geniatech_dvbs_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
 		}
 		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
 		dev->dvb.frontend = dvb_attach(s5h1409_attach,
 					       &pinnacle_pctv_hd_800i_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			/* tuner_config.video_dev must point to
 			 * i2c_adap.algo_data
 			 */
-			pinnacle_pctv_hd_800i_tuner_config.priv =
-						dev->core->i2c_adap.algo_data;
-			dvb_attach(xc5000_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap,
-				   &pinnacle_pctv_hd_800i_tuner_config);
+			if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+					&core->i2c_adap,
+					&pinnacle_pctv_hd_800i_tuner_config,
+					core->i2c_adap.algo_data))
+				goto frontend_detach;
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
 		dev->dvb.frontend = dvb_attach(s5h1409_attach,
 						&dvico_hdtv5_pci_nano_config,
-						&dev->core->i2c_adap);
+						&core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			struct dvb_frontend *fe;
 			struct xc2028_config cfg = {
-				.i2c_adap  = &dev->core->i2c_adap,
+				.i2c_adap  = &core->i2c_adap,
 				.i2c_addr  = 0x61,
 				.callback  = cx88_pci_nano_callback,
 			};
@@ -841,50 +849,50 @@
 	 case CX88_BOARD_PINNACLE_HYBRID_PCTV:
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &cx88_geniatech_x8000_mt,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (attach_xc3028(0x61, dev) < 0)
-			return -EINVAL;
+			goto frontend_detach;
 		break;
 	 case CX88_BOARD_GENIATECH_X8000_MT:
 		dev->ts_gen_cntrl = 0x00;
 
 		dev->dvb.frontend = dvb_attach(zl10353_attach,
 					       &cx88_geniatech_x8000_mt,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (attach_xc3028(0x61, dev) < 0)
-			return -EINVAL;
+			goto frontend_detach;
 		break;
 	 case CX88_BOARD_KWORLD_ATSC_120:
 		dev->dvb.frontend = dvb_attach(s5h1409_attach,
 					       &kworld_atsc_120_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (attach_xc3028(0x61, dev) < 0)
-			return -EINVAL;
+			goto frontend_detach;
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
 		dev->dvb.frontend = dvb_attach(s5h1411_attach,
 					       &dvico_fusionhdtv7_config,
-					       &dev->core->i2c_adap);
+					       &core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			/* tuner_config.video_dev must point to
 			 * i2c_adap.algo_data
 			 */
-			dvico_fusionhdtv7_tuner_config.priv =
-						dev->core->i2c_adap.algo_data;
-			dvb_attach(xc5000_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap,
-				   &dvico_fusionhdtv7_tuner_config);
+			if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+					&core->i2c_adap,
+					&dvico_fusionhdtv7_tuner_config,
+					core->i2c_adap.algo_data))
+				goto frontend_detach;
 		}
 		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
-		       dev->core->name);
+		       core->name);
 		break;
 	}
 	if (NULL == dev->dvb.frontend) {
 		printk(KERN_ERR
 		       "%s/2: frontend initialization failed\n",
-		       dev->core->name);
+		       core->name);
 		return -EINVAL;
 	}
 
@@ -892,11 +900,18 @@
 	dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
 	/* Put the analog decoder in standby to keep it quiet */
-	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+	cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
 
 	/* register everything */
 	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
 				     &dev->pci->dev, adapter_nr);
+
+frontend_detach:
+	if (dev->dvb.frontend) {
+		dvb_frontend_detach(dev->dvb.frontend);
+		dev->dvb.frontend = NULL;
+	}
+	return -EINVAL;
 }
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index c7c2896..16a5af3 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,7 +1,7 @@
 config VIDEO_EM28XX
 	tristate "Empia EM28xx USB video capture support"
 	depends on VIDEO_DEV && I2C && INPUT
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
 	select VIDEOBUF_VMALLOC
@@ -35,7 +35,6 @@
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select VIDEOBUF_DVB
-	select FW_LOADER
 	---help---
 	  This adds support for DVB cards based on the
 	  Empiatech em28xx chips.
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 50ccf37..3e4f3c7 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -420,7 +420,13 @@
 			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
 	{ USB_DEVICE(0x2040, 0x6502),
 			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
-	{ USB_DEVICE(0x2040, 0x6513),
+	{ USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x6517), /* HP  HVR-950 */
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x651b), /* RP  HVR-950 */
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
 			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
 	{ USB_DEVICE(0x0ccd, 0x0042),
 			.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 7df8157..8cf4983 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -251,7 +251,6 @@
 		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
 		       dev->name);
 		dvb_frontend_detach(dev->dvb->frontend);
-		dvb_unregister_frontend(dev->dvb->frontend);
 		dev->dvb->frontend = NULL;
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index eec115b..5d7ee8f 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,10 +1,12 @@
 config VIDEO_IVTV
 	tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+	depends on INPUT   # due to VIDEO_IR
+	depends on HOTPLUG # due to FW_LOADER
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_IR
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
 	select VIDEO_CX25840
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 8c02fa6..c7e449f 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -181,12 +181,12 @@
 		return 0;
 	}
 	/* Need sliced data for mpeg insertion */
-	if (get_service_set(itv->vbi.sliced_in) == 0) {
+	if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) {
 		if (itv->is_60hz)
 			itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
 		else
 			itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
-		expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
+		ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
 	}
 	return 0;
 }
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index ed020f7..797e636 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -853,6 +853,7 @@
 	return 0;
 }
 
+#ifdef MODULE
 static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
 		const char *name, u32 id)
 {
@@ -865,12 +866,14 @@
 	IVTV_DEBUG_INFO("Loaded module %s\n", name);
 	return hw;
 }
+#endif
 
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
 	u32 hw = itv->card->hw_all;
 	unsigned i;
 
+#ifdef MODULE
 	/* load modules */
 #ifndef CONFIG_MEDIA_TUNER
 	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
@@ -911,6 +914,7 @@
 #ifndef CONFIG_VIDEO_M52790
 	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
 #endif
+#endif
 
 	/* check which i2c devices are actually found */
 	for (i = 0; i < 32; i++) {
@@ -1228,7 +1232,7 @@
 	return 0;
 
 free_streams:
-	ivtv_streams_cleanup(itv);
+	ivtv_streams_cleanup(itv, 1);
 free_irq:
 	free_irq(itv->dev->irq, (void *)itv);
 free_i2c:
@@ -1373,7 +1377,7 @@
 	flush_workqueue(itv->irq_work_queues);
 	destroy_workqueue(itv->irq_work_queues);
 
-	ivtv_streams_cleanup(itv);
+	ivtv_streams_cleanup(itv, 1);
 	ivtv_udma_free(itv);
 
 	exit_ivtv_i2c(itv);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 2b74b0a..f2fa434 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -987,6 +987,8 @@
 	/* Find which card this open was on */
 	spin_lock(&ivtv_cards_lock);
 	for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+		if (ivtv_cards[x] == NULL)
+			continue;
 		/* find out which stream this open was on */
 		for (y = 0; y < IVTV_MAX_STREAMS; y++) {
 			s = &ivtv_cards[x]->streams[y];
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index d508b5d..26cc0f6 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -38,7 +38,7 @@
 #include <linux/dvb/audio.h>
 #include <linux/i2c-id.h>
 
-u16 service2vbi(int type)
+u16 ivtv_service2vbi(int type)
 {
 	switch (type) {
 		case V4L2_SLICED_TELETEXT_B:
@@ -88,7 +88,7 @@
 	return 0;
 }
 
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
 	u16 set = fmt->service_set;
 	int f, l;
@@ -115,7 +115,7 @@
 	return set != 0;
 }
 
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
 	int f, l;
 	u16 set = 0;
@@ -466,7 +466,7 @@
 			vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
 			vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
 		}
-		vbifmt->service_set = get_service_set(vbifmt);
+		vbifmt->service_set = ivtv_get_service_set(vbifmt);
 		break;
 	}
 
@@ -481,12 +481,12 @@
 		if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
 			vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
 						 V4L2_SLICED_VBI_525;
-			expand_service_set(vbifmt, itv->is_50hz);
+			ivtv_expand_service_set(vbifmt, itv->is_50hz);
 			break;
 		}
 
 		itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
-		vbifmt->service_set = get_service_set(vbifmt);
+		vbifmt->service_set = ivtv_get_service_set(vbifmt);
 		break;
 	}
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
@@ -640,9 +640,9 @@
 	memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
 
 	if (vbifmt->service_set)
-		expand_service_set(vbifmt, itv->is_50hz);
+		ivtv_expand_service_set(vbifmt, itv->is_50hz);
 	set = check_service_set(vbifmt, itv->is_50hz);
-	vbifmt->service_set = get_service_set(vbifmt);
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
 
 	if (!set_fmt)
 		return 0;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index a03351b..4e67f0e 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -21,9 +21,9 @@
 #ifndef IVTV_IOCTL_H
 #define IVTV_IOCTL_H
 
-u16 service2vbi(int type);
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
+u16 ivtv_service2vbi(int type);
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
 int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long arg);
 int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index 3e1deec..fc8b1ea 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -203,14 +203,14 @@
 		s->dma != PCI_DMA_NONE ? "DMA " : "",
 		s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
 
-	s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+	s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
 	if (s->sg_pending == NULL) {
 		IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
 		return -ENOMEM;
 	}
 	s->sg_pending_size = 0;
 
-	s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+	s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
 	if (s->sg_processing == NULL) {
 		IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
 		kfree(s->sg_pending);
@@ -219,7 +219,8 @@
 	}
 	s->sg_processing_size = 0;
 
-	s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+	s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
+					GFP_KERNEL|__GFP_NOWARN);
 	if (s->sg_dma == NULL) {
 		IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
 		kfree(s->sg_pending);
@@ -235,11 +236,12 @@
 
 	/* allocate stream buffers. Initially all buffers are in q_free. */
 	for (i = 0; i < s->buffers; i++) {
-		struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
+		struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
+						GFP_KERNEL|__GFP_NOWARN);
 
 		if (buf == NULL)
 			break;
-		buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
+		buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
 		if (buf->buf == NULL) {
 			kfree(buf);
 			break;
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 4ab8d36..c47c2b9 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -244,7 +244,7 @@
 		return 0;
 
 	/* One or more streams could not be initialized. Clean 'em all up. */
-	ivtv_streams_cleanup(itv);
+	ivtv_streams_cleanup(itv, 0);
 	return -ENOMEM;
 }
 
@@ -304,12 +304,12 @@
 		return 0;
 
 	/* One or more streams could not be initialized. Clean 'em all up. */
-	ivtv_streams_cleanup(itv);
+	ivtv_streams_cleanup(itv, 1);
 	return -ENOMEM;
 }
 
 /* Unregister v4l2 devices */
-void ivtv_streams_cleanup(struct ivtv *itv)
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
 {
 	int type;
 
@@ -322,8 +322,11 @@
 			continue;
 
 		ivtv_stream_free(&itv->streams[type]);
-		/* Unregister device */
-		video_unregister_device(vdev);
+		/* Unregister or release device */
+		if (unregister)
+			video_unregister_device(vdev);
+		else
+			video_device_release(vdev);
 	}
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 3d76a41..a653a51 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -23,7 +23,7 @@
 
 int ivtv_streams_setup(struct ivtv *itv);
 int ivtv_streams_register(struct ivtv *itv);
-void ivtv_streams_cleanup(struct ivtv *itv);
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister);
 
 /* Capture related */
 int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index c151bcf..71798f0 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -169,7 +169,8 @@
 			linemask[0] |= (1 << l);
 		else
 			linemask[1] |= (1 << (l - 32));
-		dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id);
+		dst[sd + 12 + line * 43] =
+			ivtv_service2vbi(itv->vbi.sliced_data[i].id);
 		memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
 		line++;
 	}
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 62f70bd..a9417f6 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -908,7 +908,7 @@
 	}
 
 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
-	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
+	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
 	if (yi->blanking_ptr) {
 		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
 	} else {
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index df789f6..73be154 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -948,7 +948,8 @@
 	}
 
 	/* Allocate the pseudo palette */
-	oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	oi->ivtvfb_info.pseudo_palette =
+		kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
 
 	if (!oi->ivtvfb_info.pseudo_palette) {
 		IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
@@ -1056,7 +1057,8 @@
 		return -EBUSY;
 	}
 
-	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+	itv->osd_info = kzalloc(sizeof(struct osd_info),
+					GFP_ATOMIC|__GFP_NOWARN);
 	if (itv->osd_info == NULL) {
 		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
 		return -ENOMEM;
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 179e470..ee43499 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -12,15 +12,12 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/gpio.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/soc_camera.h>
 
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
 /* mt9m001 i2c address 0x5d
  * The platform has to define i2c_board_info
  * and call i2c_register_board_info() */
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index d1391ac..1658fe5 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -13,15 +13,12 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/log2.h>
+#include <linux/gpio.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/soc_camera.h>
 
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
 /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
  * The platform has to define i2c_board_info
  * and call i2c_register_board_info() */
@@ -91,7 +88,7 @@
 struct mt9v022 {
 	struct i2c_client *client;
 	struct soc_camera_device icd;
-	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+	int model;	/* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
 	int switch_gpio;
 	u16 chip_control;
 	unsigned char datawidth;
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 9620c67..4482b2c 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -1,8 +1,10 @@
 config VIDEO_PVRUSB2
 	tristate "Hauppauge WinTV-PVR USB2 support"
 	depends on VIDEO_V4L2 && I2C
+	depends on VIDEO_MEDIA	# Avoids pvrusb = Y / DVB = M
+	depends on HOTPLUG	# due to FW_LOADER
 	select FW_LOADER
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
 	select VIDEO_SAA711X
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 40e4c3b..83f076a 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -3,7 +3,7 @@
 	depends on VIDEO_DEV && PCI && I2C && INPUT
 	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select CRC32
 	---help---
@@ -27,6 +27,7 @@
 config VIDEO_SAA7134_DVB
 	tristate "DVB/ATSC Support for saa7134 based TV cards"
 	depends on VIDEO_SAA7134 && DVB_CORE
+	depends on HOTPLUG	# due to FW_LOADER
 	select VIDEOBUF_DVB
 	select FW_LOADER
 	select DVB_PLL if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index eec1278..2c19cd0 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -864,7 +864,6 @@
 	struct saa7134_dev *dev;
 	struct saa7134_mpeg_ops *mops;
 	int err;
-	int mask;
 
 	if (saa7134_devcount == SAA7134_MAXBOARDS)
 		return -ENOMEM;
@@ -1065,11 +1064,6 @@
 	if (TUNER_ABSENT != dev->tuner_type)
 		saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
 
-	if (card(dev).gpiomask != 0) {
-		mask = card(dev).gpiomask;
-		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
-		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, 0);
-	}
 	return 0;
 
  fail4:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 2d16be2..469f93a 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -538,19 +538,23 @@
 	return 0;
 }
 
-static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf,
-							  struct tda827x_config *tuner_conf)
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+				struct tda1004x_config *cdec_conf,
+				struct tda827x_config *tuner_conf)
 {
 	dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
 	if (dev->dvb.frontend) {
 		if (cdec_conf->i2c_gate)
 			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-		if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address,
-							&dev->i2c_adap, tuner_conf) == NULL) {
-			wprintk("no tda827x tuner found at addr: %02x\n",
+		if (dvb_attach(tda827x_attach, dev->dvb.frontend,
+			       cdec_conf->tuner_address,
+			       &dev->i2c_adap, tuner_conf))
+			return 0;
+
+		wprintk("no tda827x tuner found at addr: %02x\n",
 				cdec_conf->tuner_address);
-		}
 	}
+	return -EINVAL;
 }
 
 /* ------------------------------------------------------------------ */
@@ -997,7 +1001,9 @@
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
-		configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -1022,36 +1028,52 @@
 		}
 		break;
 	case SAA7134_BOARD_KWORLD_DVBT_210:
-		configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2);
+		if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+					 &tda827x_cfg_2) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
-		configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &philips_tiger_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
-		configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1);
+		if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+					 &tda827x_cfg_1) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-		configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1);
+		if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+					 &tda827x_cfg_1) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
-		configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
-		if(! use_frontend) {	/* terrestrial */
-			configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0);
+		if (!use_frontend) {	/* terrestrial */
+			if (configure_tda827x_fe(dev, &lifeview_trio_config,
+						 &tda827x_cfg_0) < 0)
+				goto dettach_frontend;
 		} else {  		/* satellite */
 			dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
 			if (dev->dvb.frontend) {
 				if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
 									&dev->i2c_adap, 0) == NULL) {
 					wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
+					goto dettach_frontend;
 				}
 				if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
 										0x08, 0, 0) == NULL) {
 					wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
+					goto dettach_frontend;
 				}
 			}
 		}
@@ -1067,15 +1089,20 @@
 								&ads_duo_cfg) == NULL) {
 				wprintk("no tda827x tuner found at addr: %02x\n",
 					ads_tech_duo_config.tuner_address);
+				goto dettach_frontend;
 			}
 		}
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
-		configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
 		if (!use_frontend) {     /* terrestrial */
-			configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+			if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+						 &tda827x_cfg_0) < 0)
+				goto dettach_frontend;
 		} else {        /* satellite */
 			dev->dvb.frontend = dvb_attach(tda10086_attach,
 							&flydvbs, &dev->i2c_adap);
@@ -1086,16 +1113,20 @@
 				struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
 
 				if (dvb_attach(tda826x_attach, dev->dvb.frontend,
-						0x60, &dev->i2c_adap, 0) == NULL)
+						0x60, &dev->i2c_adap, 0) == NULL) {
 					wprintk("%s: Medion Quadro, no tda826x "
 						"found !\n", __func__);
+					goto dettach_frontend;
+				}
 				if (dev_id != 0x08) {
 					/* we need to open the i2c gate (we know it exists) */
 					fe->ops.i2c_gate_ctrl(fe, 1);
 					if (dvb_attach(isl6405_attach, fe,
-							&dev->i2c_adap, 0x08, 0, 0) == NULL)
+							&dev->i2c_adap, 0x08, 0, 0) == NULL) {
 						wprintk("%s: Medion Quadro, no ISL6405 "
 							"found !\n", __func__);
+						goto dettach_frontend;
+					}
 					if (dev_id == 0x07) {
 						/* fire up the 2nd section of the LNB supply since
 						   we can't do this from the other section */
@@ -1117,19 +1148,17 @@
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
 					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
+		if (dev->dvb.frontend)
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   NULL, DVB_PLL_TDHU2);
-		}
 		break;
 	case SAA7134_BOARD_KWORLD_ATSC110:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
 					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
+		if (dev->dvb.frontend)
 			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
 				   &dev->i2c_adap, 0x61,
 				   TUNER_PHILIPS_TUV1236D);
-		}
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
 		dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
@@ -1138,10 +1167,12 @@
 			if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
 				       &dev->i2c_adap, 0) == NULL) {
 				wprintk("%s: No tda826x found!\n", __func__);
+				goto dettach_frontend;
 			}
 			if (dvb_attach(isl6421_attach, dev->dvb.frontend,
 				       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
 				wprintk("%s: No ISL6421 found!\n", __func__);
+				goto dettach_frontend;
 			}
 		}
 		break;
@@ -1168,43 +1199,65 @@
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
-		configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &cinergy_ht_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER_S:
-		configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+		if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+					 &tda827x_cfg_2) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_ASUS_P7131_4871:
-		configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2);
+		if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+					 &tda827x_cfg_2) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
-		configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2);
+		if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+					 &tda827x_cfg_2) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
-		configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
-		configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42);
+		if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+					 &tda827x_cfg_2_sw42) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_PHILIPS_SNAKE:
 		dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
 						&dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
-					&dev->i2c_adap, 0) == NULL)
+					&dev->i2c_adap, 0) == NULL) {
 				wprintk("%s: No tda826x found!\n", __func__);
+				goto dettach_frontend;
+			}
 			if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
-					&dev->i2c_adap, 0, 0) == NULL)
+					&dev->i2c_adap, 0, 0) == NULL) {
 				wprintk("%s: No lnbp21 found!\n", __func__);
+				goto dettach_frontend;
+			}
 		}
 		break;
 	case SAA7134_BOARD_CREATIX_CTX953:
-		configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+		if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+					 &tda827x_cfg_0) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
-		configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+		if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+					 &tda827x_cfg_2) < 0)
+			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
 		dev->dvb.frontend = dvb_attach(mt352_attach,
@@ -1218,16 +1271,20 @@
 		if (dev->dvb.frontend) {
 			struct dvb_frontend *fe;
 			if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL)
+				  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
 				wprintk("%s: MD7134 DVB-S, no SD1878 "
 					"found !\n", __func__);
+				goto dettach_frontend;
+			}
 			/* we need to open the i2c gate (we know it exists) */
 			fe = dev->dvb.frontend;
 			fe->ops.i2c_gate_ctrl(fe, 1);
 			if (dvb_attach(isl6405_attach, fe,
-					&dev->i2c_adap, 0x08, 0, 0) == NULL)
+					&dev->i2c_adap, 0x08, 0, 0) == NULL) {
 				wprintk("%s: MD7134 DVB-S, no ISL6405 "
 					"found !\n", __func__);
+				goto dettach_frontend;
+			}
 			fe->ops.i2c_gate_ctrl(fe, 0);
 			dev->original_set_voltage = fe->ops.set_voltage;
 			fe->ops.set_voltage = md8800_set_voltage;
@@ -1254,10 +1311,7 @@
 		if (!fe) {
 			printk(KERN_ERR "%s/2: xc3028 attach failed\n",
 			       dev->name);
-			dvb_frontend_detach(dev->dvb.frontend);
-			dvb_unregister_frontend(dev->dvb.frontend);
-			dev->dvb.frontend = NULL;
-			return -1;
+			goto dettach_frontend;
 		}
 	}
 
@@ -1282,6 +1336,12 @@
 			dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
 	}
 	return ret;
+
+dettach_frontend:
+	dvb_frontend_detach(dev->dvb.frontend);
+	dev->dvb.frontend = NULL;
+
+	return -1;
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index 9276ed9..b12c60c 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -30,6 +30,7 @@
 #include <linux/kref.h>
 
 #include <linux/usb.h>
+#include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
@@ -245,6 +246,8 @@
 		return -1;
 }
 
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+
 /* sysfs functions */
 /*FIXME cleanup this */
 
@@ -350,6 +353,10 @@
 	video_device_remove_file(vdev, &dev_attr_vflip);
 }
 
+#else
+#define stk_create_sysfs_files(a)
+#define stk_remove_sysfs_files(a)
+#endif
 
 /* *********************************************** */
 /*
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 6bf104e..5a75788 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -40,11 +40,11 @@
 	typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
 	if (__a) { \
 		__r = (int) __a(ARGS); \
+		symbol_put(FUNCTION); \
 	} else { \
 		printk(KERN_ERR "TUNER: Unable to find " \
 				"symbol "#FUNCTION"()\n"); \
 	} \
-	symbol_put(FUNCTION); \
 	__r; \
 })
 
@@ -340,16 +340,6 @@
 	tuner_warn("====================== WARNING! ======================\n");
 }
 
-static void attach_tda829x(struct tuner *t)
-{
-	struct tda829x_config cfg = {
-		.lna_cfg        = t->config,
-		.tuner_callback = t->tuner_callback,
-	};
-	dvb_attach(tda829x_attach,
-		   &t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-}
-
 static struct xc5000_config xc5000_cfg;
 
 static void set_type(struct i2c_client *c, unsigned int type,
@@ -385,12 +375,19 @@
 
 	switch (t->type) {
 	case TUNER_MT2032:
-		dvb_attach(microtune_attach,
-			   &t->fe, t->i2c->adapter, t->i2c->addr);
+		if (!dvb_attach(microtune_attach,
+			   &t->fe, t->i2c->adapter, t->i2c->addr))
+			goto attach_failed;
 		break;
 	case TUNER_PHILIPS_TDA8290:
 	{
-		attach_tda829x(t);
+		struct tda829x_config cfg = {
+			.lna_cfg        = t->config,
+			.tuner_callback = t->tuner_callback,
+		};
+		if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
+				t->i2c->addr, &cfg))
+			goto attach_failed;
 		break;
 	}
 	case TUNER_TEA5767:
@@ -441,8 +438,9 @@
 		break;
 	}
 	case TUNER_TDA9887:
-		dvb_attach(tda9887_attach,
-			   &t->fe, t->i2c->adapter, t->i2c->addr);
+		if (!dvb_attach(tda9887_attach,
+			   &t->fe, t->i2c->adapter, t->i2c->addr))
+			goto attach_failed;
 		break;
 	case TUNER_XC5000:
 	{
@@ -450,10 +448,10 @@
 
 		xc5000_cfg.i2c_address	  = t->i2c->addr;
 		xc5000_cfg.if_khz	  = 5380;
-		xc5000_cfg.priv           = c->adapter->algo_data;
 		xc5000_cfg.tuner_callback = t->tuner_callback;
 		if (!dvb_attach(xc5000_attach,
-				&t->fe, t->i2c->adapter, &xc5000_cfg))
+				&t->fe, t->i2c->adapter, &xc5000_cfg,
+				c->adapter->algo_data))
 			goto attach_failed;
 
 		xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -1167,7 +1165,7 @@
 			/* If chip is not tda8290, don't register.
 			   since it can be tda9887*/
 			if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
-					       t->i2c->addr) == 0) {
+					       t->i2c->addr) >= 0) {
 				tuner_dbg("tda829x detected\n");
 			} else {
 				/* Default is being tda9887 */
@@ -1181,7 +1179,7 @@
 		case 0x60:
 			if (tuner_symbol_probe(tea5767_autodetection,
 					       t->i2c->adapter, t->i2c->addr)
-					!= EINVAL) {
+					>= 0) {
 				t->type = TUNER_TEA5767;
 				t->mode_mask = T_RADIO;
 				t->mode = T_STANDBY;
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 3cf8a8e..9da0e18 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -319,10 +319,12 @@
 	{AUDIO_CHIP_INTERNAL, "CX25843"},
 	{AUDIO_CHIP_INTERNAL, "CX23418"},
 	{AUDIO_CHIP_INTERNAL, "CX23885"},
-	/* 40-42 */
+	/* 40-44 */
 	{AUDIO_CHIP_INTERNAL, "CX23888"},
 	{AUDIO_CHIP_INTERNAL, "SAA7131"},
 	{AUDIO_CHIP_INTERNAL, "CX23887"},
+	{AUDIO_CHIP_INTERNAL, "SAA7164"},
+	{AUDIO_CHIP_INTERNAL, "AU8522"},
 };
 
 /* This list is supplied by Hauppauge. Thanks! */
@@ -341,8 +343,10 @@
 	"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
 	/* 30-34 */
 	"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
-	/* 35-37 */
-	"SAA7131", "CX25837", "CX23887"
+	/* 35-39 */
+	"SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
+	/* 40-42 */
+	"SAA7164", "CX23885B", "AU8522"
 };
 
 static int hasRadioTuner(int tunerType)
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
index 74e1d30..fc24ef0 100644
--- a/drivers/media/video/usbvision/Kconfig
+++ b/drivers/media/video/usbvision/Kconfig
@@ -1,7 +1,7 @@
 config VIDEO_USBVISION
 	tristate "USB video devices based on Nogatech NT1003/1004/1005"
 	depends on I2C && VIDEO_V4L2
-	select MEDIA_TUNER
+	select VIDEO_TUNER
 	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  There are more than 50 different USB video devices based on
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index 5515234..03a87a3 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -157,215 +157,136 @@
 /*
  * Define the return values and values passed to user's callout functions.
  * (It is important to add new value codes at the end just preceding
- * xpcUnknownReason, which must have the highest numerical value.)
+ * xpUnknownReason, which must have the highest numerical value.)
  */
-enum xpc_retval {
-	xpcSuccess = 0,
+enum xp_retval {
+	xpSuccess = 0,
 
-	xpcNotConnected,	/*  1: channel is not connected */
-	xpcConnected,		/*  2: channel connected (opened) */
-	xpcRETIRED1,		/*  3: (formerly xpcDisconnected) */
+	xpNotConnected,		/*  1: channel is not connected */
+	xpConnected,		/*  2: channel connected (opened) */
+	xpRETIRED1,		/*  3: (formerly xpDisconnected) */
 
-	xpcMsgReceived,		/*  4: message received */
-	xpcMsgDelivered,	/*  5: message delivered and acknowledged */
+	xpMsgReceived,		/*  4: message received */
+	xpMsgDelivered,		/*  5: message delivered and acknowledged */
 
-	xpcRETIRED2,		/*  6: (formerly xpcTransferFailed) */
+	xpRETIRED2,		/*  6: (formerly xpTransferFailed) */
 
-	xpcNoWait,		/*  7: operation would require wait */
-	xpcRetry,		/*  8: retry operation */
-	xpcTimeout,		/*  9: timeout in xpc_allocate_msg_wait() */
-	xpcInterrupted,		/* 10: interrupted wait */
+	xpNoWait,		/*  7: operation would require wait */
+	xpRetry,		/*  8: retry operation */
+	xpTimeout,		/*  9: timeout in xpc_allocate_msg_wait() */
+	xpInterrupted,		/* 10: interrupted wait */
 
-	xpcUnequalMsgSizes,	/* 11: message size disparity between sides */
-	xpcInvalidAddress,	/* 12: invalid address */
+	xpUnequalMsgSizes,	/* 11: message size disparity between sides */
+	xpInvalidAddress,	/* 12: invalid address */
 
-	xpcNoMemory,		/* 13: no memory available for XPC structures */
-	xpcLackOfResources,	/* 14: insufficient resources for operation */
-	xpcUnregistered,	/* 15: channel is not registered */
-	xpcAlreadyRegistered,	/* 16: channel is already registered */
+	xpNoMemory,		/* 13: no memory available for XPC structures */
+	xpLackOfResources,	/* 14: insufficient resources for operation */
+	xpUnregistered,		/* 15: channel is not registered */
+	xpAlreadyRegistered,	/* 16: channel is already registered */
 
-	xpcPartitionDown,	/* 17: remote partition is down */
-	xpcNotLoaded,		/* 18: XPC module is not loaded */
-	xpcUnloading,		/* 19: this side is unloading XPC module */
+	xpPartitionDown,	/* 17: remote partition is down */
+	xpNotLoaded,		/* 18: XPC module is not loaded */
+	xpUnloading,		/* 19: this side is unloading XPC module */
 
-	xpcBadMagic,		/* 20: XPC MAGIC string not found */
+	xpBadMagic,		/* 20: XPC MAGIC string not found */
 
-	xpcReactivating,	/* 21: remote partition was reactivated */
+	xpReactivating,		/* 21: remote partition was reactivated */
 
-	xpcUnregistering,	/* 22: this side is unregistering channel */
-	xpcOtherUnregistering,	/* 23: other side is unregistering channel */
+	xpUnregistering,	/* 22: this side is unregistering channel */
+	xpOtherUnregistering,	/* 23: other side is unregistering channel */
 
-	xpcCloneKThread,	/* 24: cloning kernel thread */
-	xpcCloneKThreadFailed,	/* 25: cloning kernel thread failed */
+	xpCloneKThread,		/* 24: cloning kernel thread */
+	xpCloneKThreadFailed,	/* 25: cloning kernel thread failed */
 
-	xpcNoHeartbeat,		/* 26: remote partition has no heartbeat */
+	xpNoHeartbeat,		/* 26: remote partition has no heartbeat */
 
-	xpcPioReadError,	/* 27: PIO read error */
-	xpcPhysAddrRegFailed,	/* 28: registration of phys addr range failed */
+	xpPioReadError,		/* 27: PIO read error */
+	xpPhysAddrRegFailed,	/* 28: registration of phys addr range failed */
 
-	xpcBteDirectoryError,	/* 29: maps to BTEFAIL_DIR */
-	xpcBtePoisonError,	/* 30: maps to BTEFAIL_POISON */
-	xpcBteWriteError,	/* 31: maps to BTEFAIL_WERR */
-	xpcBteAccessError,	/* 32: maps to BTEFAIL_ACCESS */
-	xpcBtePWriteError,	/* 33: maps to BTEFAIL_PWERR */
-	xpcBtePReadError,	/* 34: maps to BTEFAIL_PRERR */
-	xpcBteTimeOutError,	/* 35: maps to BTEFAIL_TOUT */
-	xpcBteXtalkError,	/* 36: maps to BTEFAIL_XTERR */
-	xpcBteNotAvailable,	/* 37: maps to BTEFAIL_NOTAVAIL */
-	xpcBteUnmappedError,	/* 38: unmapped BTEFAIL_ error */
+	xpRETIRED3,		/* 29: (formerly xpBteDirectoryError) */
+	xpRETIRED4,		/* 30: (formerly xpBtePoisonError) */
+	xpRETIRED5,		/* 31: (formerly xpBteWriteError) */
+	xpRETIRED6,		/* 32: (formerly xpBteAccessError) */
+	xpRETIRED7,		/* 33: (formerly xpBtePWriteError) */
+	xpRETIRED8,		/* 34: (formerly xpBtePReadError) */
+	xpRETIRED9,		/* 35: (formerly xpBteTimeOutError) */
+	xpRETIRED10,		/* 36: (formerly xpBteXtalkError) */
+	xpRETIRED11,		/* 37: (formerly xpBteNotAvailable) */
+	xpRETIRED12,		/* 38: (formerly xpBteUnmappedError) */
 
-	xpcBadVersion,		/* 39: bad version number */
-	xpcVarsNotSet,		/* 40: the XPC variables are not set up */
-	xpcNoRsvdPageAddr,	/* 41: unable to get rsvd page's phys addr */
-	xpcInvalidPartid,	/* 42: invalid partition ID */
-	xpcLocalPartid,		/* 43: local partition ID */
+	xpBadVersion,		/* 39: bad version number */
+	xpVarsNotSet,		/* 40: the XPC variables are not set up */
+	xpNoRsvdPageAddr,	/* 41: unable to get rsvd page's phys addr */
+	xpInvalidPartid,	/* 42: invalid partition ID */
+	xpLocalPartid,		/* 43: local partition ID */
 
-	xpcOtherGoingDown,	/* 44: other side going down, reason unknown */
-	xpcSystemGoingDown,	/* 45: system is going down, reason unknown */
-	xpcSystemHalt,		/* 46: system is being halted */
-	xpcSystemReboot,	/* 47: system is being rebooted */
-	xpcSystemPoweroff,	/* 48: system is being powered off */
+	xpOtherGoingDown,	/* 44: other side going down, reason unknown */
+	xpSystemGoingDown,	/* 45: system is going down, reason unknown */
+	xpSystemHalt,		/* 46: system is being halted */
+	xpSystemReboot,		/* 47: system is being rebooted */
+	xpSystemPoweroff,	/* 48: system is being powered off */
 
-	xpcDisconnecting,	/* 49: channel disconnecting (closing) */
+	xpDisconnecting,	/* 49: channel disconnecting (closing) */
 
-	xpcOpenCloseError,	/* 50: channel open/close protocol error */
+	xpOpenCloseError,	/* 50: channel open/close protocol error */
 
-	xpcDisconnected,	/* 51: channel disconnected (closed) */
+	xpDisconnected,		/* 51: channel disconnected (closed) */
 
-	xpcBteSh2Start,		/* 52: BTE CRB timeout */
+	xpBteCopyError,		/* 52: bte_copy() returned error */
 
-				/* 53: 0x1 BTE Error Response Short */
-	xpcBteSh2RspShort = xpcBteSh2Start + BTEFAIL_SH2_RESP_SHORT,
-
-				/* 54: 0x2 BTE Error Response Long */
-	xpcBteSh2RspLong = xpcBteSh2Start + BTEFAIL_SH2_RESP_LONG,
-
-				/* 56: 0x4 BTE Error Response DSB */
-	xpcBteSh2RspDSB = xpcBteSh2Start + BTEFAIL_SH2_RESP_DSP,
-
-				/* 60: 0x8 BTE Error Response Access */
-	xpcBteSh2RspAccess = xpcBteSh2Start + BTEFAIL_SH2_RESP_ACCESS,
-
-				/* 68: 0x10 BTE Error CRB timeout */
-	xpcBteSh2CRBTO = xpcBteSh2Start + BTEFAIL_SH2_CRB_TO,
-
-				/* 84: 0x20 BTE Error NACK limit */
-	xpcBteSh2NACKLimit = xpcBteSh2Start + BTEFAIL_SH2_NACK_LIMIT,
-
-				/* 115: BTE end */
-	xpcBteSh2End = xpcBteSh2Start + BTEFAIL_SH2_ALL,
-
-	xpcUnknownReason	/* 116: unknown reason - must be last in enum */
+	xpUnknownReason		/* 53: unknown reason - must be last in enum */
 };
 
 /*
- * Define the callout function types used by XPC to update the user on
- * connection activity and state changes (via the user function registered by
- * xpc_connect()) and to notify them of messages received and delivered (via
- * the user function registered by xpc_send_notify()).
- *
- * The two function types are xpc_channel_func and xpc_notify_func and
- * both share the following arguments, with the exception of "data", which
- * only xpc_channel_func has.
+ * Define the callout function type used by XPC to update the user on
+ * connection activity and state changes via the user function registered
+ * by xpc_connect().
  *
  * Arguments:
  *
- *	reason - reason code. (See following table.)
+ *	reason - reason code.
  *	partid - partition ID associated with condition.
  *	ch_number - channel # associated with condition.
- *	data - pointer to optional data. (See following table.)
+ *	data - pointer to optional data.
  *	key - pointer to optional user-defined value provided as the "key"
- *	      argument to xpc_connect() or xpc_send_notify().
+ *	      argument to xpc_connect().
  *
- * In the following table the "Optional Data" column applies to callouts made
- * to functions registered by xpc_connect(). A "NA" in that column indicates
- * that this reason code can be passed to functions registered by
- * xpc_send_notify() (i.e. they don't have data arguments).
+ * A reason code of xpConnected indicates that a connection has been
+ * established to the specified partition on the specified channel. The data
+ * argument indicates the max number of entries allowed in the message queue.
  *
- * Also, the first three reason codes in the following table indicate
- * success, whereas the others indicate failure. When a failure reason code
- * is received, one can assume that the channel is not connected.
+ * A reason code of xpMsgReceived indicates that a XPC message arrived from
+ * the specified partition on the specified channel. The data argument
+ * specifies the address of the message's payload. The user must call
+ * xpc_received() when finished with the payload.
  *
- *
- * Reason Code          | Cause                          | Optional Data
- * =====================+================================+=====================
- * xpcConnected         | connection has been established| max #of entries
- *                      | to the specified partition on  | allowed in message
- *                      | the specified channel          | queue
- * ---------------------+--------------------------------+---------------------
- * xpcMsgReceived       | an XPC message arrived from    | address of payload
- *                      | the specified partition on the |
- *                      | specified channel              | [the user must call
- *                      |                                | xpc_received() when
- *                      |                                | finished with the
- *                      |                                | payload]
- * ---------------------+--------------------------------+---------------------
- * xpcMsgDelivered      | notification that the message  | NA
- *                      | was delivered to the intended  |
- *                      | recipient and that they have   |
- *                      | acknowledged its receipt by    |
- *                      | calling xpc_received()         |
- * =====================+================================+=====================
- * xpcUnequalMsgSizes   | can't connect to the specified | NULL
- *                      | partition on the specified     |
- *                      | channel because of mismatched  |
- *                      | message sizes                  |
- * ---------------------+--------------------------------+---------------------
- * xpcNoMemory          | insufficient memory avaiable   | NULL
- *                      | to allocate message queue      |
- * ---------------------+--------------------------------+---------------------
- * xpcLackOfResources   | lack of resources to create    | NULL
- *                      | the necessary kthreads to      |
- *                      | support the channel            |
- * ---------------------+--------------------------------+---------------------
- * xpcUnregistering     | this side's user has           | NULL or NA
- *                      | unregistered by calling        |
- *                      | xpc_disconnect()               |
- * ---------------------+--------------------------------+---------------------
- * xpcOtherUnregistering| the other side's user has      | NULL or NA
- *                      | unregistered by calling        |
- *                      | xpc_disconnect()               |
- * ---------------------+--------------------------------+---------------------
- * xpcNoHeartbeat       | the other side's XPC is no     | NULL or NA
- *                      | longer heartbeating            |
- *                      |                                |
- * ---------------------+--------------------------------+---------------------
- * xpcUnloading         | this side's XPC module is      | NULL or NA
- *                      | being unloaded                 |
- *                      |                                |
- * ---------------------+--------------------------------+---------------------
- * xpcOtherUnloading    | the other side's XPC module is | NULL or NA
- *                      | is being unloaded              |
- *                      |                                |
- * ---------------------+--------------------------------+---------------------
- * xpcPioReadError      | xp_nofault_PIOR() returned an  | NULL or NA
- *                      | error while sending an IPI     |
- *                      |                                |
- * ---------------------+--------------------------------+---------------------
- * xpcInvalidAddress    | the address either received or | NULL or NA
- *                      | sent by the specified partition|
- *                      | is invalid                     |
- * ---------------------+--------------------------------+---------------------
- * xpcBteNotAvailable   | attempt to pull data from the  | NULL or NA
- * xpcBtePoisonError    | specified partition over the   |
- * xpcBteWriteError     | specified channel via a        |
- * xpcBteAccessError    | bte_copy() failed              |
- * xpcBteTimeOutError   |                                |
- * xpcBteXtalkError     |                                |
- * xpcBteDirectoryError |                                |
- * xpcBteGenericError   |                                |
- * xpcBteUnmappedError  |                                |
- * ---------------------+--------------------------------+---------------------
- * xpcUnknownReason     | the specified channel to the   | NULL or NA
- *                      | specified partition was        |
- *                      | unavailable for unknown reasons|
- * =====================+================================+=====================
+ * All other reason codes indicate failure. The data argmument is NULL.
+ * When a failure reason code is received, one can assume that the channel
+ * is not connected.
  */
-
-typedef void (*xpc_channel_func) (enum xpc_retval reason, partid_t partid,
+typedef void (*xpc_channel_func) (enum xp_retval reason, short partid,
 				  int ch_number, void *data, void *key);
 
-typedef void (*xpc_notify_func) (enum xpc_retval reason, partid_t partid,
+/*
+ * Define the callout function type used by XPC to notify the user of
+ * messages received and delivered via the user function registered by
+ * xpc_send_notify().
+ *
+ * Arguments:
+ *
+ *	reason - reason code.
+ *	partid - partition ID associated with condition.
+ *	ch_number - channel # associated with condition.
+ *	key - pointer to optional user-defined value provided as the "key"
+ *	      argument to xpc_send_notify().
+ *
+ * A reason code of xpMsgDelivered indicates that the message was delivered
+ * to the intended recipient and that they have acknowledged its receipt by
+ * calling xpc_received().
+ *
+ * All other reason codes indicate failure.
+ */
+typedef void (*xpc_notify_func) (enum xp_retval reason, short partid,
 				 int ch_number, void *key);
 
 /*
@@ -401,57 +322,57 @@
 struct xpc_interface {
 	void (*connect) (int);
 	void (*disconnect) (int);
-	enum xpc_retval (*allocate) (partid_t, int, u32, void **);
-	enum xpc_retval (*send) (partid_t, int, void *);
-	enum xpc_retval (*send_notify) (partid_t, int, void *,
+	enum xp_retval (*allocate) (short, int, u32, void **);
+	enum xp_retval (*send) (short, int, void *);
+	enum xp_retval (*send_notify) (short, int, void *,
 					xpc_notify_func, void *);
-	void (*received) (partid_t, int, void *);
-	enum xpc_retval (*partid_to_nasids) (partid_t, void *);
+	void (*received) (short, int, void *);
+	enum xp_retval (*partid_to_nasids) (short, void *);
 };
 
 extern struct xpc_interface xpc_interface;
 
 extern void xpc_set_interface(void (*)(int),
 			      void (*)(int),
-			      enum xpc_retval (*)(partid_t, int, u32, void **),
-			      enum xpc_retval (*)(partid_t, int, void *),
-			      enum xpc_retval (*)(partid_t, int, void *,
+			      enum xp_retval (*)(short, int, u32, void **),
+			      enum xp_retval (*)(short, int, void *),
+			      enum xp_retval (*)(short, int, void *,
 						  xpc_notify_func, void *),
-			      void (*)(partid_t, int, void *),
-			      enum xpc_retval (*)(partid_t, void *));
+			      void (*)(short, int, void *),
+			      enum xp_retval (*)(short, void *));
 extern void xpc_clear_interface(void);
 
-extern enum xpc_retval xpc_connect(int, xpc_channel_func, void *, u16,
+extern enum xp_retval xpc_connect(int, xpc_channel_func, void *, u16,
 				   u16, u32, u32);
 extern void xpc_disconnect(int);
 
-static inline enum xpc_retval
-xpc_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+static inline enum xp_retval
+xpc_allocate(short partid, int ch_number, u32 flags, void **payload)
 {
 	return xpc_interface.allocate(partid, ch_number, flags, payload);
 }
 
-static inline enum xpc_retval
-xpc_send(partid_t partid, int ch_number, void *payload)
+static inline enum xp_retval
+xpc_send(short partid, int ch_number, void *payload)
 {
 	return xpc_interface.send(partid, ch_number, payload);
 }
 
-static inline enum xpc_retval
-xpc_send_notify(partid_t partid, int ch_number, void *payload,
+static inline enum xp_retval
+xpc_send_notify(short partid, int ch_number, void *payload,
 		xpc_notify_func func, void *key)
 {
 	return xpc_interface.send_notify(partid, ch_number, payload, func, key);
 }
 
 static inline void
-xpc_received(partid_t partid, int ch_number, void *payload)
+xpc_received(short partid, int ch_number, void *payload)
 {
 	return xpc_interface.received(partid, ch_number, payload);
 }
 
-static inline enum xpc_retval
-xpc_partid_to_nasids(partid_t partid, void *nasids)
+static inline enum xp_retval
+xpc_partid_to_nasids(short partid, void *nasids)
 {
 	return xpc_interface.partid_to_nasids(partid, nasids);
 }
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c
index 1fbf99b..196480b 100644
--- a/drivers/misc/sgi-xp/xp_main.c
+++ b/drivers/misc/sgi-xp/xp_main.c
@@ -42,21 +42,21 @@
 /*
  * Initialize the XPC interface to indicate that XPC isn't loaded.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_notloaded(void)
 {
-	return xpcNotLoaded;
+	return xpNotLoaded;
 }
 
 struct xpc_interface xpc_interface = {
 	(void (*)(int))xpc_notloaded,
 	(void (*)(int))xpc_notloaded,
-	(enum xpc_retval(*)(partid_t, int, u32, void **))xpc_notloaded,
-	(enum xpc_retval(*)(partid_t, int, void *))xpc_notloaded,
-	(enum xpc_retval(*)(partid_t, int, void *, xpc_notify_func, void *))
+	(enum xp_retval(*)(short, int, u32, void **))xpc_notloaded,
+	(enum xp_retval(*)(short, int, void *))xpc_notloaded,
+	(enum xp_retval(*)(short, int, void *, xpc_notify_func, void *))
 	    xpc_notloaded,
-	(void (*)(partid_t, int, void *))xpc_notloaded,
-	(enum xpc_retval(*)(partid_t, void *))xpc_notloaded
+	(void (*)(short, int, void *))xpc_notloaded,
+	(enum xp_retval(*)(short, void *))xpc_notloaded
 };
 EXPORT_SYMBOL_GPL(xpc_interface);
 
@@ -66,12 +66,12 @@
 void
 xpc_set_interface(void (*connect) (int),
 		  void (*disconnect) (int),
-		  enum xpc_retval (*allocate) (partid_t, int, u32, void **),
-		  enum xpc_retval (*send) (partid_t, int, void *),
-		  enum xpc_retval (*send_notify) (partid_t, int, void *,
+		  enum xp_retval (*allocate) (short, int, u32, void **),
+		  enum xp_retval (*send) (short, int, void *),
+		  enum xp_retval (*send_notify) (short, int, void *,
 						  xpc_notify_func, void *),
-		  void (*received) (partid_t, int, void *),
-		  enum xpc_retval (*partid_to_nasids) (partid_t, void *))
+		  void (*received) (short, int, void *),
+		  enum xp_retval (*partid_to_nasids) (short, void *))
 {
 	xpc_interface.connect = connect;
 	xpc_interface.disconnect = disconnect;
@@ -91,16 +91,16 @@
 {
 	xpc_interface.connect = (void (*)(int))xpc_notloaded;
 	xpc_interface.disconnect = (void (*)(int))xpc_notloaded;
-	xpc_interface.allocate = (enum xpc_retval(*)(partid_t, int, u32,
+	xpc_interface.allocate = (enum xp_retval(*)(short, int, u32,
 						     void **))xpc_notloaded;
-	xpc_interface.send = (enum xpc_retval(*)(partid_t, int, void *))
+	xpc_interface.send = (enum xp_retval(*)(short, int, void *))
 	    xpc_notloaded;
-	xpc_interface.send_notify = (enum xpc_retval(*)(partid_t, int, void *,
+	xpc_interface.send_notify = (enum xp_retval(*)(short, int, void *,
 							xpc_notify_func,
 							void *))xpc_notloaded;
-	xpc_interface.received = (void (*)(partid_t, int, void *))
+	xpc_interface.received = (void (*)(short, int, void *))
 	    xpc_notloaded;
-	xpc_interface.partid_to_nasids = (enum xpc_retval(*)(partid_t, void *))
+	xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *))
 	    xpc_notloaded;
 }
 EXPORT_SYMBOL_GPL(xpc_clear_interface);
@@ -123,13 +123,13 @@
  *	nentries - max #of XPC message entries a message queue can contain.
  *		   The actual number, which is determined when a connection
  * 		   is established and may be less then requested, will be
- *		   passed to the user via the xpcConnected callout.
+ *		   passed to the user via the xpConnected callout.
  *	assigned_limit - max number of kthreads allowed to be processing
  * 			 messages (per connection) at any given instant.
  *	idle_limit - max number of kthreads allowed to be idle at any given
  * 		     instant.
  */
-enum xpc_retval
+enum xp_retval
 xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
 	    u16 nentries, u32 assigned_limit, u32 idle_limit)
 {
@@ -143,12 +143,12 @@
 	registration = &xpc_registrations[ch_number];
 
 	if (mutex_lock_interruptible(&registration->mutex) != 0)
-		return xpcInterrupted;
+		return xpInterrupted;
 
 	/* if XPC_CHANNEL_REGISTERED(ch_number) */
 	if (registration->func != NULL) {
 		mutex_unlock(&registration->mutex);
-		return xpcAlreadyRegistered;
+		return xpAlreadyRegistered;
 	}
 
 	/* register the channel for connection */
@@ -163,7 +163,7 @@
 
 	xpc_interface.connect(ch_number);
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 EXPORT_SYMBOL_GPL(xpc_connect);
 
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h
index 9eb6d4a..11ac267 100644
--- a/drivers/misc/sgi-xp/xpc.h
+++ b/drivers/misc/sgi-xp/xpc.h
@@ -172,13 +172,13 @@
 			(_version >= _XPC_VERSION(3, 1))
 
 static inline int
-xpc_hb_allowed(partid_t partid, struct xpc_vars *vars)
+xpc_hb_allowed(short partid, struct xpc_vars *vars)
 {
 	return ((vars->heartbeating_to_mask & (1UL << partid)) != 0);
 }
 
 static inline void
-xpc_allow_hb(partid_t partid, struct xpc_vars *vars)
+xpc_allow_hb(short partid, struct xpc_vars *vars)
 {
 	u64 old_mask, new_mask;
 
@@ -190,7 +190,7 @@
 }
 
 static inline void
-xpc_disallow_hb(partid_t partid, struct xpc_vars *vars)
+xpc_disallow_hb(short partid, struct xpc_vars *vars)
 {
 	u64 old_mask, new_mask;
 
@@ -408,11 +408,11 @@
  *	messages.
  */
 struct xpc_channel {
-	partid_t partid;	/* ID of remote partition connected */
+	short partid;		/* ID of remote partition connected */
 	spinlock_t lock;	/* lock for updating this structure */
 	u32 flags;		/* general flags */
 
-	enum xpc_retval reason;	/* reason why channel is disconnect'g */
+	enum xp_retval reason;	/* reason why channel is disconnect'g */
 	int reason_line;	/* line# disconnect initiated from */
 
 	u16 number;		/* channel # */
@@ -522,7 +522,7 @@
 	spinlock_t act_lock;	/* protect updating of act_state */
 	u8 act_state;		/* from XPC HB viewpoint */
 	u8 remote_vars_version;	/* version# of partition's vars */
-	enum xpc_retval reason;	/* reason partition is deactivating */
+	enum xp_retval reason;	/* reason partition is deactivating */
 	int reason_line;	/* line# deactivation initiated from */
 	int reactivate_nasid;	/* nasid in partition to reactivate */
 
@@ -615,7 +615,7 @@
 /* interval in seconds to print 'waiting disengagement' messages */
 #define XPC_DISENGAGE_PRINTMSG_INTERVAL		10
 
-#define XPC_PARTID(_p)	((partid_t) ((_p) - &xpc_partitions[0]))
+#define XPC_PARTID(_p)	((short)((_p) - &xpc_partitions[0]))
 
 /* found in xp_main.c */
 extern struct xpc_registration xpc_registrations[];
@@ -646,31 +646,31 @@
 extern void xpc_restrict_IPI_ops(void);
 extern int xpc_identify_act_IRQ_sender(void);
 extern int xpc_partition_disengaged(struct xpc_partition *);
-extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *);
+extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *);
 extern void xpc_mark_partition_inactive(struct xpc_partition *);
 extern void xpc_discovery(void);
 extern void xpc_check_remote_hb(void);
 extern void xpc_deactivate_partition(const int, struct xpc_partition *,
-				     enum xpc_retval);
-extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *);
+				     enum xp_retval);
+extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *);
 
 /* found in xpc_channel.c */
 extern void xpc_initiate_connect(int);
 extern void xpc_initiate_disconnect(int);
-extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **);
-extern enum xpc_retval xpc_initiate_send(partid_t, int, void *);
-extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *,
-						xpc_notify_func, void *);
-extern void xpc_initiate_received(partid_t, int, void *);
-extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *);
-extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *);
+extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **);
+extern enum xp_retval xpc_initiate_send(short, int, void *);
+extern enum xp_retval xpc_initiate_send_notify(short, int, void *,
+					       xpc_notify_func, void *);
+extern void xpc_initiate_received(short, int, void *);
+extern enum xp_retval xpc_setup_infrastructure(struct xpc_partition *);
+extern enum xp_retval xpc_pull_remote_vars_part(struct xpc_partition *);
 extern void xpc_process_channel_activity(struct xpc_partition *);
 extern void xpc_connected_callout(struct xpc_channel *);
 extern void xpc_deliver_msg(struct xpc_channel *);
 extern void xpc_disconnect_channel(const int, struct xpc_channel *,
-				   enum xpc_retval, unsigned long *);
-extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval);
-extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval);
+				   enum xp_retval, unsigned long *);
+extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval);
+extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval);
 extern void xpc_teardown_infrastructure(struct xpc_partition *);
 
 static inline void
@@ -901,7 +901,7 @@
 	return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR);
 }
 
-static inline enum xpc_retval
+static inline enum xp_retval
 xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
 {
 	int ret = 0;
@@ -923,7 +923,7 @@
 
 	local_irq_restore(irq_flags);
 
-	return ((ret == 0) ? xpcSuccess : xpcPioReadError);
+	return ((ret == 0) ? xpSuccess : xpPioReadError);
 }
 
 /*
@@ -992,7 +992,7 @@
 		    unsigned long *irq_flags)
 {
 	struct xpc_partition *part = &xpc_partitions[ch->partid];
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	if (likely(part->act_state != XPC_P_DEACTIVATING)) {
 		ret = xpc_IPI_send(part->remote_IPI_amo_va,
@@ -1001,7 +1001,7 @@
 				   part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY);
 		dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
 			ipi_flag_string, ch->partid, ch->number, ret);
-		if (unlikely(ret != xpcSuccess)) {
+		if (unlikely(ret != xpSuccess)) {
 			if (irq_flags != NULL)
 				spin_unlock_irqrestore(&ch->lock, *irq_flags);
 			XPC_DEACTIVATE_PARTITION(part, ret);
@@ -1123,41 +1123,10 @@
 	return amo;
 }
 
-static inline enum xpc_retval
+static inline enum xp_retval
 xpc_map_bte_errors(bte_result_t error)
 {
-	if (error == BTE_SUCCESS)
-		return xpcSuccess;
-
-	if (is_shub2()) {
-		if (BTE_VALID_SH2_ERROR(error))
-			return xpcBteSh2Start + error;
-		return xpcBteUnmappedError;
-	}
-	switch (error) {
-	case BTE_SUCCESS:
-		return xpcSuccess;
-	case BTEFAIL_DIR:
-		return xpcBteDirectoryError;
-	case BTEFAIL_POISON:
-		return xpcBtePoisonError;
-	case BTEFAIL_WERR:
-		return xpcBteWriteError;
-	case BTEFAIL_ACCESS:
-		return xpcBteAccessError;
-	case BTEFAIL_PWERR:
-		return xpcBtePWriteError;
-	case BTEFAIL_PRERR:
-		return xpcBtePReadError;
-	case BTEFAIL_TOUT:
-		return xpcBteTimeOutError;
-	case BTEFAIL_XTERR:
-		return xpcBteXtalkError;
-	case BTEFAIL_NOTAVAIL:
-		return xpcBteNotAvailable;
-	default:
-		return xpcBteUnmappedError;
-	}
+	return ((error == BTE_SUCCESS) ? xpSuccess : xpBteCopyError);
 }
 
 /*
diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c
index bfcb9ea..9c90c2d 100644
--- a/drivers/misc/sgi-xp/xpc_channel.c
+++ b/drivers/misc/sgi-xp/xpc_channel.c
@@ -53,7 +53,7 @@
  * Set up the initial values for the XPartition Communication channels.
  */
 static void
-xpc_initialize_channels(struct xpc_partition *part, partid_t partid)
+xpc_initialize_channels(struct xpc_partition *part, short partid)
 {
 	int ch_number;
 	struct xpc_channel *ch;
@@ -90,12 +90,12 @@
  * Setup the infrastructure necessary to support XPartition Communication
  * between the specified remote partition and the local one.
  */
-enum xpc_retval
+enum xp_retval
 xpc_setup_infrastructure(struct xpc_partition *part)
 {
 	int ret, cpuid;
 	struct timer_list *timer;
-	partid_t partid = XPC_PARTID(part);
+	short partid = XPC_PARTID(part);
 
 	/*
 	 * Zero out MOST of the entry for this partition. Only the fields
@@ -114,7 +114,7 @@
 				 GFP_KERNEL);
 	if (part->channels == NULL) {
 		dev_err(xpc_chan, "can't get memory for channels\n");
-		return xpcNoMemory;
+		return xpNoMemory;
 	}
 
 	part->nchannels = XPC_NCHANNELS;
@@ -129,7 +129,7 @@
 		part->channels = NULL;
 		dev_err(xpc_chan, "can't get memory for local get/put "
 			"values\n");
-		return xpcNoMemory;
+		return xpNoMemory;
 	}
 
 	part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE,
@@ -143,7 +143,7 @@
 		part->local_GPs = NULL;
 		kfree(part->channels);
 		part->channels = NULL;
-		return xpcNoMemory;
+		return xpNoMemory;
 	}
 
 	/* allocate all the required open and close args */
@@ -159,7 +159,7 @@
 		part->local_GPs = NULL;
 		kfree(part->channels);
 		part->channels = NULL;
-		return xpcNoMemory;
+		return xpNoMemory;
 	}
 
 	part->remote_openclose_args =
@@ -175,7 +175,7 @@
 		part->local_GPs = NULL;
 		kfree(part->channels);
 		part->channels = NULL;
-		return xpcNoMemory;
+		return xpNoMemory;
 	}
 
 	xpc_initialize_channels(part, partid);
@@ -209,7 +209,7 @@
 		part->local_GPs = NULL;
 		kfree(part->channels);
 		part->channels = NULL;
-		return xpcLackOfResources;
+		return xpLackOfResources;
 	}
 
 	/* Setup a timer to check for dropped IPIs */
@@ -243,7 +243,7 @@
 	xpc_vars_part[partid].nchannels = part->nchannels;
 	xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -254,7 +254,7 @@
  * dst must be a cacheline aligned virtual address on this partition.
  * cnt must be an cacheline sized
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst,
 			   const void *src, size_t cnt)
 {
@@ -270,7 +270,7 @@
 	bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt,
 			      (BTE_NORMAL | BTE_WACQUIRE), NULL);
 	if (bte_ret == BTE_SUCCESS)
-		return xpcSuccess;
+		return xpSuccess;
 
 	dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n",
 		XPC_PARTID(part), bte_ret);
@@ -282,7 +282,7 @@
  * Pull the remote per partition specific variables from the specified
  * partition.
  */
-enum xpc_retval
+enum xp_retval
 xpc_pull_remote_vars_part(struct xpc_partition *part)
 {
 	u8 buffer[L1_CACHE_BYTES * 2];
@@ -290,8 +290,8 @@
 	    (struct xpc_vars_part *)L1_CACHE_ALIGN((u64)buffer);
 	struct xpc_vars_part *pulled_entry;
 	u64 remote_entry_cacheline_pa, remote_entry_pa;
-	partid_t partid = XPC_PARTID(part);
-	enum xpc_retval ret;
+	short partid = XPC_PARTID(part);
+	enum xp_retval ret;
 
 	/* pull the cacheline that contains the variables we're interested in */
 
@@ -311,7 +311,7 @@
 	ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline,
 					 (void *)remote_entry_cacheline_pa,
 					 L1_CACHE_BYTES);
-	if (ret != xpcSuccess) {
+	if (ret != xpSuccess) {
 		dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
 			"partition %d, ret=%d\n", partid, ret);
 		return ret;
@@ -326,11 +326,11 @@
 			dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
 				"partition %d has bad magic value (=0x%lx)\n",
 				partid, sn_partition_id, pulled_entry->magic);
-			return xpcBadMagic;
+			return xpBadMagic;
 		}
 
 		/* they've not been initialized yet */
-		return xpcRetry;
+		return xpRetry;
 	}
 
 	if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) {
@@ -344,7 +344,7 @@
 			dev_err(xpc_chan, "partition %d's XPC vars_part for "
 				"partition %d are not valid\n", partid,
 				sn_partition_id);
-			return xpcInvalidAddress;
+			return xpInvalidAddress;
 		}
 
 		/* the variables we imported look to be valid */
@@ -366,9 +366,9 @@
 	}
 
 	if (pulled_entry->magic == XPC_VP_MAGIC1)
-		return xpcRetry;
+		return xpRetry;
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -379,7 +379,7 @@
 {
 	unsigned long irq_flags;
 	u64 IPI_amo;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	/*
 	 * See if there are any IPI flags to be handled.
@@ -398,7 +398,7 @@
 						 (void *)part->
 						 remote_openclose_args_pa,
 						 XPC_OPENCLOSE_ARGS_SIZE);
-		if (ret != xpcSuccess) {
+		if (ret != xpSuccess) {
 			XPC_DEACTIVATE_PARTITION(part, ret);
 
 			dev_dbg(xpc_chan, "failed to pull openclose args from "
@@ -414,7 +414,7 @@
 		ret = xpc_pull_remote_cachelines(part, part->remote_GPs,
 						 (void *)part->remote_GPs_pa,
 						 XPC_GP_SIZE);
-		if (ret != xpcSuccess) {
+		if (ret != xpSuccess) {
 			XPC_DEACTIVATE_PARTITION(part, ret);
 
 			dev_dbg(xpc_chan, "failed to pull GPs from partition "
@@ -431,7 +431,7 @@
 /*
  * Allocate the local message queue and the notify queue.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_allocate_local_msgqueue(struct xpc_channel *ch)
 {
 	unsigned long irq_flags;
@@ -464,18 +464,18 @@
 			ch->local_nentries = nentries;
 		}
 		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		return xpcSuccess;
+		return xpSuccess;
 	}
 
 	dev_dbg(xpc_chan, "can't get memory for local message queue and notify "
 		"queue, partid=%d, channel=%d\n", ch->partid, ch->number);
-	return xpcNoMemory;
+	return xpNoMemory;
 }
 
 /*
  * Allocate the cached remote message queue.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
 {
 	unsigned long irq_flags;
@@ -502,12 +502,12 @@
 			ch->remote_nentries = nentries;
 		}
 		spin_unlock_irqrestore(&ch->lock, irq_flags);
-		return xpcSuccess;
+		return xpSuccess;
 	}
 
 	dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "
 		"partid=%d, channel=%d\n", ch->partid, ch->number);
-	return xpcNoMemory;
+	return xpNoMemory;
 }
 
 /*
@@ -515,20 +515,20 @@
  *
  * Note: Assumes all of the channel sizes are filled in.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_allocate_msgqueues(struct xpc_channel *ch)
 {
 	unsigned long irq_flags;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	DBUG_ON(ch->flags & XPC_C_SETUP);
 
 	ret = xpc_allocate_local_msgqueue(ch);
-	if (ret != xpcSuccess)
+	if (ret != xpSuccess)
 		return ret;
 
 	ret = xpc_allocate_remote_msgqueue(ch);
-	if (ret != xpcSuccess) {
+	if (ret != xpSuccess) {
 		kfree(ch->local_msgqueue_base);
 		ch->local_msgqueue = NULL;
 		kfree(ch->notify_queue);
@@ -540,7 +540,7 @@
 	ch->flags |= XPC_C_SETUP;
 	spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -552,7 +552,7 @@
 static void
 xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
 {
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	DBUG_ON(!spin_is_locked(&ch->lock));
 
@@ -568,7 +568,7 @@
 		ret = xpc_allocate_msgqueues(ch);
 		spin_lock_irqsave(&ch->lock, *irq_flags);
 
-		if (ret != xpcSuccess)
+		if (ret != xpSuccess)
 			XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags);
 
 		if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING))
@@ -603,7 +603,7 @@
  * Notify those who wanted to be notified upon delivery of their message.
  */
 static void
-xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put)
+xpc_notify_senders(struct xpc_channel *ch, enum xp_retval reason, s64 put)
 {
 	struct xpc_notify *notify;
 	u8 notify_type;
@@ -748,7 +748,7 @@
 
 	if (ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE) {
 		spin_unlock_irqrestore(&ch->lock, *irq_flags);
-		xpc_disconnect_callout(ch, xpcDisconnected);
+		xpc_disconnect_callout(ch, xpDisconnected);
 		spin_lock_irqsave(&ch->lock, *irq_flags);
 	}
 
@@ -791,7 +791,7 @@
 	struct xpc_openclose_args *args =
 	    &part->remote_openclose_args[ch_number];
 	struct xpc_channel *ch = &part->channels[ch_number];
-	enum xpc_retval reason;
+	enum xp_retval reason;
 
 	spin_lock_irqsave(&ch->lock, irq_flags);
 
@@ -871,10 +871,10 @@
 
 		if (!(ch->flags & XPC_C_DISCONNECTING)) {
 			reason = args->reason;
-			if (reason <= xpcSuccess || reason > xpcUnknownReason)
-				reason = xpcUnknownReason;
-			else if (reason == xpcUnregistering)
-				reason = xpcOtherUnregistering;
+			if (reason <= xpSuccess || reason > xpUnknownReason)
+				reason = xpUnknownReason;
+			else if (reason == xpUnregistering)
+				reason = xpOtherUnregistering;
 
 			XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
 
@@ -961,7 +961,7 @@
 
 		if (ch->flags & XPC_C_OPENREQUEST) {
 			if (args->msg_size != ch->msg_size) {
-				XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+				XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
 						       &irq_flags);
 				spin_unlock_irqrestore(&ch->lock, irq_flags);
 				return;
@@ -991,7 +991,7 @@
 			return;
 		}
 		if (!(ch->flags & XPC_C_OPENREQUEST)) {
-			XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError,
+			XPC_DISCONNECT_CHANNEL(ch, xpOpenCloseError,
 					       &irq_flags);
 			spin_unlock_irqrestore(&ch->lock, irq_flags);
 			return;
@@ -1042,18 +1042,18 @@
 /*
  * Attempt to establish a channel connection to a remote partition.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_connect_channel(struct xpc_channel *ch)
 {
 	unsigned long irq_flags;
 	struct xpc_registration *registration = &xpc_registrations[ch->number];
 
 	if (mutex_trylock(&registration->mutex) == 0)
-		return xpcRetry;
+		return xpRetry;
 
 	if (!XPC_CHANNEL_REGISTERED(ch->number)) {
 		mutex_unlock(&registration->mutex);
-		return xpcUnregistered;
+		return xpUnregistered;
 	}
 
 	spin_lock_irqsave(&ch->lock, irq_flags);
@@ -1095,10 +1095,10 @@
 			 * the channel lock as needed.
 			 */
 			mutex_unlock(&registration->mutex);
-			XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+			XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
 					       &irq_flags);
 			spin_unlock_irqrestore(&ch->lock, irq_flags);
-			return xpcUnequalMsgSizes;
+			return xpUnequalMsgSizes;
 		}
 	} else {
 		ch->msg_size = registration->msg_size;
@@ -1120,7 +1120,7 @@
 
 	spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -1203,7 +1203,7 @@
 			 * Notify senders that messages sent have been
 			 * received and delivered by the other side.
 			 */
-			xpc_notify_senders(ch, xpcMsgDelivered,
+			xpc_notify_senders(ch, xpMsgDelivered,
 					   ch->remote_GP.get);
 		}
 
@@ -1335,7 +1335,7 @@
  * at the same time.
  */
 void
-xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason)
+xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason)
 {
 	unsigned long irq_flags;
 	int ch_number;
@@ -1375,7 +1375,7 @@
 void
 xpc_teardown_infrastructure(struct xpc_partition *part)
 {
-	partid_t partid = XPC_PARTID(part);
+	short partid = XPC_PARTID(part);
 
 	/*
 	 * We start off by making this partition inaccessible to local
@@ -1428,7 +1428,7 @@
 void
 xpc_initiate_connect(int ch_number)
 {
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
 	struct xpc_channel *ch;
 
@@ -1456,13 +1456,13 @@
 	/* let the registerer know that a connection has been established */
 
 	if (ch->func != NULL) {
-		dev_dbg(xpc_chan, "ch->func() called, reason=xpcConnected, "
+		dev_dbg(xpc_chan, "ch->func() called, reason=xpConnected, "
 			"partid=%d, channel=%d\n", ch->partid, ch->number);
 
-		ch->func(xpcConnected, ch->partid, ch->number,
+		ch->func(xpConnected, ch->partid, ch->number,
 			 (void *)(u64)ch->local_nentries, ch->key);
 
-		dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, "
+		dev_dbg(xpc_chan, "ch->func() returned, reason=xpConnected, "
 			"partid=%d, channel=%d\n", ch->partid, ch->number);
 	}
 }
@@ -1484,7 +1484,7 @@
 xpc_initiate_disconnect(int ch_number)
 {
 	unsigned long irq_flags;
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
 	struct xpc_channel *ch;
 
@@ -1503,7 +1503,7 @@
 			if (!(ch->flags & XPC_C_DISCONNECTED)) {
 				ch->flags |= XPC_C_WDISCONNECT;
 
-				XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering,
+				XPC_DISCONNECT_CHANNEL(ch, xpUnregistering,
 						       &irq_flags);
 			}
 
@@ -1528,7 +1528,7 @@
  */
 void
 xpc_disconnect_channel(const int line, struct xpc_channel *ch,
-		       enum xpc_retval reason, unsigned long *irq_flags)
+		       enum xp_retval reason, unsigned long *irq_flags)
 {
 	u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED);
 
@@ -1563,7 +1563,7 @@
 
 	} else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
 		   !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
-		/* start a kthread that will do the xpcDisconnecting callout */
+		/* start a kthread that will do the xpDisconnecting callout */
 		xpc_create_kthreads(ch, 1, 1);
 	}
 
@@ -1575,7 +1575,7 @@
 }
 
 void
-xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason)
+xpc_disconnect_callout(struct xpc_channel *ch, enum xp_retval reason)
 {
 	/*
 	 * Let the channel's registerer know that the channel is being
@@ -1598,13 +1598,13 @@
  * Wait for a message entry to become available for the specified channel,
  * but don't wait any longer than 1 jiffy.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_allocate_msg_wait(struct xpc_channel *ch)
 {
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	if (ch->flags & XPC_C_DISCONNECTING) {
-		DBUG_ON(ch->reason == xpcInterrupted);
+		DBUG_ON(ch->reason == xpInterrupted);
 		return ch->reason;
 	}
 
@@ -1614,11 +1614,11 @@
 
 	if (ch->flags & XPC_C_DISCONNECTING) {
 		ret = ch->reason;
-		DBUG_ON(ch->reason == xpcInterrupted);
+		DBUG_ON(ch->reason == xpInterrupted);
 	} else if (ret == 0) {
-		ret = xpcTimeout;
+		ret = xpTimeout;
 	} else {
-		ret = xpcInterrupted;
+		ret = xpInterrupted;
 	}
 
 	return ret;
@@ -1628,12 +1628,12 @@
  * Allocate an entry for a message from the message queue associated with the
  * specified channel.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
 		 struct xpc_msg **address_of_msg)
 {
 	struct xpc_msg *msg;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 	s64 put;
 
 	/* this reference will be dropped in xpc_send_msg() */
@@ -1645,7 +1645,7 @@
 	}
 	if (!(ch->flags & XPC_C_CONNECTED)) {
 		xpc_msgqueue_deref(ch);
-		return xpcNotConnected;
+		return xpNotConnected;
 	}
 
 	/*
@@ -1653,7 +1653,7 @@
 	 * If none are available, we'll make sure that we grab the latest
 	 * GP values.
 	 */
-	ret = xpcTimeout;
+	ret = xpTimeout;
 
 	while (1) {
 
@@ -1683,16 +1683,16 @@
 		 * that will cause the IPI handler to fetch the latest
 		 * GP values as if an IPI was sent by the other side.
 		 */
-		if (ret == xpcTimeout)
+		if (ret == xpTimeout)
 			xpc_IPI_send_local_msgrequest(ch);
 
 		if (flags & XPC_NOWAIT) {
 			xpc_msgqueue_deref(ch);
-			return xpcNoWait;
+			return xpNoWait;
 		}
 
 		ret = xpc_allocate_msg_wait(ch);
-		if (ret != xpcInterrupted && ret != xpcTimeout) {
+		if (ret != xpInterrupted && ret != xpTimeout) {
 			xpc_msgqueue_deref(ch);
 			return ret;
 		}
@@ -1711,7 +1711,7 @@
 
 	*address_of_msg = msg;
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -1727,11 +1727,11 @@
  *	payload - address of the allocated payload area pointer (filled in on
  * 	          return) in which the user-defined message is constructed.
  */
-enum xpc_retval
-xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+enum xp_retval
+xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload)
 {
 	struct xpc_partition *part = &xpc_partitions[partid];
-	enum xpc_retval ret = xpcUnknownReason;
+	enum xp_retval ret = xpUnknownReason;
 	struct xpc_msg *msg = NULL;
 
 	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
@@ -1814,11 +1814,11 @@
  * local message queue's Put value and sends an IPI to the partition the
  * message is being sent to.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
 	     xpc_notify_func func, void *key)
 {
-	enum xpc_retval ret = xpcSuccess;
+	enum xp_retval ret = xpSuccess;
 	struct xpc_notify *notify = notify;
 	s64 put, msg_number = msg->number;
 
@@ -1908,12 +1908,12 @@
  *	payload - pointer to the payload area allocated via
  *			xpc_initiate_allocate().
  */
-enum xpc_retval
-xpc_initiate_send(partid_t partid, int ch_number, void *payload)
+enum xp_retval
+xpc_initiate_send(short partid, int ch_number, void *payload)
 {
 	struct xpc_partition *part = &xpc_partitions[partid];
 	struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg,
 		partid, ch_number);
@@ -1957,13 +1957,13 @@
  *		  receipt. THIS FUNCTION MUST BE NON-BLOCKING.
  *	key - user-defined key to be passed to the function when it's called.
  */
-enum xpc_retval
-xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload,
+enum xp_retval
+xpc_initiate_send_notify(short partid, int ch_number, void *payload,
 			 xpc_notify_func func, void *key)
 {
 	struct xpc_partition *part = &xpc_partitions[partid];
 	struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg,
 		partid, ch_number);
@@ -1985,7 +1985,7 @@
 	struct xpc_msg *remote_msg, *msg;
 	u32 msg_index, nmsgs;
 	u64 msg_offset;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) {
 		/* we were interrupted by a signal */
@@ -2012,7 +2012,7 @@
 
 		ret = xpc_pull_remote_cachelines(part, msg, remote_msg,
 						 nmsgs * ch->msg_size);
-		if (ret != xpcSuccess) {
+		if (ret != xpSuccess) {
 
 			dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
 				" msg %ld from partition %d, channel=%d, "
@@ -2112,7 +2112,7 @@
 				ch->number);
 
 			/* deliver the message to its intended recipient */
-			ch->func(xpcMsgReceived, ch->partid, ch->number,
+			ch->func(xpMsgReceived, ch->partid, ch->number,
 				 &msg->payload, ch->key);
 
 			dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
@@ -2203,7 +2203,7 @@
  *			xpc_initiate_allocate().
  */
 void
-xpc_initiate_received(partid_t partid, int ch_number, void *payload)
+xpc_initiate_received(short partid, int ch_number, void *payload)
 {
 	struct xpc_partition *part = &xpc_partitions[partid];
 	struct xpc_channel *ch;
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index f673ba9..08256ed 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -315,13 +315,13 @@
  * the XPC per partition variables from the remote partition and waiting for
  * the remote partition to pull ours.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_make_first_contact(struct xpc_partition *part)
 {
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
-	while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) {
-		if (ret != xpcRetry) {
+	while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) {
+		if (ret != xpRetry) {
 			XPC_DEACTIVATE_PARTITION(part, ret);
 			return ret;
 		}
@@ -406,7 +406,7 @@
 
 	dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part));
 
-	if (xpc_setup_infrastructure(part) != xpcSuccess)
+	if (xpc_setup_infrastructure(part) != xpSuccess)
 		return;
 
 	/*
@@ -418,7 +418,7 @@
 
 	(void)xpc_part_ref(part);	/* this will always succeed */
 
-	if (xpc_make_first_contact(part) == xpcSuccess)
+	if (xpc_make_first_contact(part) == xpSuccess)
 		xpc_channel_mgr(part);
 
 	xpc_part_deref(part);
@@ -429,7 +429,7 @@
 static int
 xpc_activating(void *__partid)
 {
-	partid_t partid = (u64)__partid;
+	short partid = (u64)__partid;
 	struct xpc_partition *part = &xpc_partitions[partid];
 	unsigned long irq_flags;
 
@@ -470,7 +470,7 @@
 
 		spin_lock_irqsave(&part->act_lock, irq_flags);
 		part->act_state = XPC_P_INACTIVE;
-		XPC_SET_REASON(part, xpcPhysAddrRegFailed, __LINE__);
+		XPC_SET_REASON(part, xpPhysAddrRegFailed, __LINE__);
 		spin_unlock_irqrestore(&part->act_lock, irq_flags);
 		part->remote_rp_pa = 0;
 		return 0;
@@ -488,7 +488,7 @@
 	xpc_disallow_hb(partid, xpc_vars);
 	xpc_mark_partition_inactive(part);
 
-	if (part->reason == xpcReactivating) {
+	if (part->reason == xpReactivating) {
 		/* interrupting ourselves results in activating partition */
 		xpc_IPI_send_reactivate(part);
 	}
@@ -499,7 +499,7 @@
 void
 xpc_activate_partition(struct xpc_partition *part)
 {
-	partid_t partid = XPC_PARTID(part);
+	short partid = XPC_PARTID(part);
 	unsigned long irq_flags;
 	struct task_struct *kthread;
 
@@ -508,7 +508,7 @@
 	DBUG_ON(part->act_state != XPC_P_INACTIVE);
 
 	part->act_state = XPC_P_ACTIVATION_REQ;
-	XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
+	XPC_SET_REASON(part, xpCloneKThread, __LINE__);
 
 	spin_unlock_irqrestore(&part->act_lock, irq_flags);
 
@@ -517,7 +517,7 @@
 	if (IS_ERR(kthread)) {
 		spin_lock_irqsave(&part->act_lock, irq_flags);
 		part->act_state = XPC_P_INACTIVE;
-		XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
+		XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__);
 		spin_unlock_irqrestore(&part->act_lock, irq_flags);
 	}
 }
@@ -541,7 +541,7 @@
 irqreturn_t
 xpc_notify_IRQ_handler(int irq, void *dev_id)
 {
-	partid_t partid = (partid_t) (u64)dev_id;
+	short partid = (short)(u64)dev_id;
 	struct xpc_partition *part = &xpc_partitions[partid];
 
 	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
@@ -643,7 +643,7 @@
 static int
 xpc_kthread_start(void *args)
 {
-	partid_t partid = XPC_UNPACK_ARG1(args);
+	short partid = XPC_UNPACK_ARG1(args);
 	u16 ch_number = XPC_UNPACK_ARG2(args);
 	struct xpc_partition *part = &xpc_partitions[partid];
 	struct xpc_channel *ch;
@@ -696,7 +696,7 @@
 		ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
 		spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-		xpc_disconnect_callout(ch, xpcDisconnecting);
+		xpc_disconnect_callout(ch, xpDisconnecting);
 
 		spin_lock_irqsave(&ch->lock, irq_flags);
 		ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
@@ -776,7 +776,7 @@
 			 * then we'll deadlock if all other kthreads assigned
 			 * to this channel are blocked in the channel's
 			 * registerer, because the only thing that will unblock
-			 * them is the xpcDisconnecting callout that this
+			 * them is the xpDisconnecting callout that this
 			 * failed kthread_run() would have made.
 			 */
 
@@ -796,7 +796,7 @@
 				 * to function.
 				 */
 				spin_lock_irqsave(&ch->lock, irq_flags);
-				XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
+				XPC_DISCONNECT_CHANNEL(ch, xpLackOfResources,
 						       &irq_flags);
 				spin_unlock_irqrestore(&ch->lock, irq_flags);
 			}
@@ -809,7 +809,7 @@
 xpc_disconnect_wait(int ch_number)
 {
 	unsigned long irq_flags;
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
 	struct xpc_channel *ch;
 	int wakeup_channel_mgr;
@@ -857,9 +857,9 @@
 }
 
 static void
-xpc_do_exit(enum xpc_retval reason)
+xpc_do_exit(enum xp_retval reason)
 {
-	partid_t partid;
+	short partid;
 	int active_part_count, printed_waiting_msg = 0;
 	struct xpc_partition *part;
 	unsigned long printmsg_time, disengage_request_timeout = 0;
@@ -955,7 +955,7 @@
 	del_timer_sync(&xpc_hb_timer);
 	DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
 
-	if (reason == xpcUnloading) {
+	if (reason == xpUnloading) {
 		/* take ourselves off of the reboot_notifier_list */
 		(void)unregister_reboot_notifier(&xpc_reboot_notifier);
 
@@ -981,20 +981,20 @@
 static int
 xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
 {
-	enum xpc_retval reason;
+	enum xp_retval reason;
 
 	switch (event) {
 	case SYS_RESTART:
-		reason = xpcSystemReboot;
+		reason = xpSystemReboot;
 		break;
 	case SYS_HALT:
-		reason = xpcSystemHalt;
+		reason = xpSystemHalt;
 		break;
 	case SYS_POWER_OFF:
-		reason = xpcSystemPoweroff;
+		reason = xpSystemPoweroff;
 		break;
 	default:
-		reason = xpcSystemGoingDown;
+		reason = xpSystemGoingDown;
 	}
 
 	xpc_do_exit(reason);
@@ -1008,7 +1008,7 @@
 xpc_die_disengage(void)
 {
 	struct xpc_partition *part;
-	partid_t partid;
+	short partid;
 	unsigned long engaged;
 	long time, printmsg_time, disengage_request_timeout;
 
@@ -1124,7 +1124,7 @@
 xpc_init(void)
 {
 	int ret;
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
 	struct task_struct *kthread;
 	size_t buf_size;
@@ -1279,7 +1279,7 @@
 		/* mark this new thread as a non-starter */
 		complete(&xpc_discovery_exited);
 
-		xpc_do_exit(xpcUnloading);
+		xpc_do_exit(xpUnloading);
 		return -EBUSY;
 	}
 
@@ -1297,7 +1297,7 @@
 void __exit
 xpc_exit(void)
 {
-	xpc_do_exit(xpcUnloading);
+	xpc_do_exit(xpUnloading);
 }
 
 module_exit(xpc_exit);
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index acd3fd4..7dd4b58 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -403,7 +403,7 @@
 {
 	struct xpc_vars *remote_vars;
 	struct xpc_partition *part;
-	partid_t partid;
+	short partid;
 	bte_result_t bres;
 
 	remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer;
@@ -444,7 +444,7 @@
 		     (remote_vars->heartbeat_offline == 0)) ||
 		    !xpc_hb_allowed(sn_partition_id, remote_vars)) {
 
-			XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
+			XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat);
 			continue;
 		}
 
@@ -459,7 +459,7 @@
  * is large enough to contain a copy of their reserved page header and
  * part_nasids mask.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
 		  struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa)
 {
@@ -469,7 +469,7 @@
 
 	*remote_rp_pa = xpc_get_rsvd_page_pa(nasid);
 	if (*remote_rp_pa == 0)
-		return xpcNoRsvdPageAddr;
+		return xpNoRsvdPageAddr;
 
 	/* pull over the reserved page header and part_nasids mask */
 	bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp,
@@ -489,18 +489,18 @@
 
 	if (remote_rp->partid < 1 ||
 	    remote_rp->partid > (XP_MAX_PARTITIONS - 1)) {
-		return xpcInvalidPartid;
+		return xpInvalidPartid;
 	}
 
 	if (remote_rp->partid == sn_partition_id)
-		return xpcLocalPartid;
+		return xpLocalPartid;
 
 	if (XPC_VERSION_MAJOR(remote_rp->version) !=
 	    XPC_VERSION_MAJOR(XPC_RP_VERSION)) {
-		return xpcBadVersion;
+		return xpBadVersion;
 	}
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -509,13 +509,13 @@
  * remote_vars points to a buffer that is cacheline aligned for BTE copies and
  * assumed to be of size XPC_RP_VARS_SIZE.
  */
-static enum xpc_retval
+static enum xp_retval
 xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
 {
 	int bres;
 
 	if (remote_vars_pa == 0)
-		return xpcVarsNotSet;
+		return xpVarsNotSet;
 
 	/* pull over the cross partition variables */
 	bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE,
@@ -525,10 +525,10 @@
 
 	if (XPC_VERSION_MAJOR(remote_vars->version) !=
 	    XPC_VERSION_MAJOR(XPC_V_VERSION)) {
-		return xpcBadVersion;
+		return xpBadVersion;
 	}
 
-	return xpcSuccess;
+	return xpSuccess;
 }
 
 /*
@@ -604,16 +604,16 @@
 	int reactivate = 0;
 	int stamp_diff;
 	struct timespec remote_rp_stamp = { 0, 0 };
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	/* pull over the reserved page structure */
 
 	remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer;
 
 	ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa);
-	if (ret != xpcSuccess) {
+	if (ret != xpSuccess) {
 		dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
 			 "which sent interrupt, reason=%d\n", nasid, ret);
 		return;
@@ -632,7 +632,7 @@
 	remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer;
 
 	ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
-	if (ret != xpcSuccess) {
+	if (ret != xpSuccess) {
 
 		dev_warn(xpc_part, "unable to get XPC variables from nasid %d, "
 			 "which sent interrupt, reason=%d\n", nasid, ret);
@@ -699,7 +699,7 @@
 					  &remote_rp_stamp, remote_rp_pa,
 					  remote_vars_pa, remote_vars);
 		part->reactivate_nasid = nasid;
-		XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
+		XPC_DEACTIVATE_PARTITION(part, xpReactivating);
 		return;
 	}
 
@@ -754,11 +754,11 @@
 
 	if (reactivate) {
 		part->reactivate_nasid = nasid;
-		XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
+		XPC_DEACTIVATE_PARTITION(part, xpReactivating);
 
 	} else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) &&
 		   xpc_partition_disengage_requested(1UL << partid)) {
-		XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown);
+		XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown);
 	}
 }
 
@@ -825,7 +825,7 @@
 int
 xpc_partition_disengaged(struct xpc_partition *part)
 {
-	partid_t partid = XPC_PARTID(part);
+	short partid = XPC_PARTID(part);
 	int disengaged;
 
 	disengaged = (xpc_partition_engaged(1UL << partid) == 0);
@@ -870,20 +870,20 @@
 /*
  * Mark specified partition as active.
  */
-enum xpc_retval
+enum xp_retval
 xpc_mark_partition_active(struct xpc_partition *part)
 {
 	unsigned long irq_flags;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part));
 
 	spin_lock_irqsave(&part->act_lock, irq_flags);
 	if (part->act_state == XPC_P_ACTIVATING) {
 		part->act_state = XPC_P_ACTIVE;
-		ret = xpcSuccess;
+		ret = xpSuccess;
 	} else {
-		DBUG_ON(part->reason == xpcSuccess);
+		DBUG_ON(part->reason == xpSuccess);
 		ret = part->reason;
 	}
 	spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -896,7 +896,7 @@
  */
 void
 xpc_deactivate_partition(const int line, struct xpc_partition *part,
-			 enum xpc_retval reason)
+			 enum xp_retval reason)
 {
 	unsigned long irq_flags;
 
@@ -905,15 +905,15 @@
 	if (part->act_state == XPC_P_INACTIVE) {
 		XPC_SET_REASON(part, reason, line);
 		spin_unlock_irqrestore(&part->act_lock, irq_flags);
-		if (reason == xpcReactivating) {
+		if (reason == xpReactivating) {
 			/* we interrupt ourselves to reactivate partition */
 			xpc_IPI_send_reactivate(part);
 		}
 		return;
 	}
 	if (part->act_state == XPC_P_DEACTIVATING) {
-		if ((part->reason == xpcUnloading && reason != xpcUnloading) ||
-		    reason == xpcReactivating) {
+		if ((part->reason == xpUnloading && reason != xpUnloading) ||
+		    reason == xpReactivating) {
 			XPC_SET_REASON(part, reason, line);
 		}
 		spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -982,10 +982,10 @@
 	int max_regions;
 	int nasid;
 	struct xpc_rsvd_page *rp;
-	partid_t partid;
+	short partid;
 	struct xpc_partition *part;
 	u64 *discovered_nasids;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE +
 						  xp_nasid_mask_bytes,
@@ -1063,12 +1063,12 @@
 
 			ret = xpc_get_remote_rp(nasid, discovered_nasids,
 						remote_rp, &remote_rp_pa);
-			if (ret != xpcSuccess) {
+			if (ret != xpSuccess) {
 				dev_dbg(xpc_part, "unable to get reserved page "
 					"from nasid %d, reason=%d\n", nasid,
 					ret);
 
-				if (ret == xpcLocalPartid)
+				if (ret == xpLocalPartid)
 					break;
 
 				continue;
@@ -1082,7 +1082,7 @@
 			/* pull over the cross partition variables */
 
 			ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
-			if (ret != xpcSuccess) {
+			if (ret != xpSuccess) {
 				dev_dbg(xpc_part, "unable to get XPC variables "
 					"from nasid %d, reason=%d\n", nasid,
 					ret);
@@ -1116,7 +1116,7 @@
 					"register xp_addr region 0x%016lx\n",
 					partid, remote_vars->amos_page_pa);
 
-				XPC_SET_REASON(part, xpcPhysAddrRegFailed,
+				XPC_SET_REASON(part, xpPhysAddrRegFailed,
 					       __LINE__);
 				break;
 			}
@@ -1151,8 +1151,8 @@
  * Given a partid, get the nasids owned by that partition from the
  * remote partition's reserved page.
  */
-enum xpc_retval
-xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask)
+enum xp_retval
+xpc_initiate_partid_to_nasids(short partid, void *nasid_mask)
 {
 	struct xpc_partition *part;
 	u64 part_nasid_pa;
@@ -1160,7 +1160,7 @@
 
 	part = &xpc_partitions[partid];
 	if (part->remote_rp_pa == 0)
-		return xpcPartitionDown;
+		return xpPartitionDown;
 
 	memset(nasid_mask, 0, XP_NASID_MASK_BYTES);
 
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index a9543c6..822dc8e 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -166,7 +166,7 @@
  * Packet was recevied by XPC and forwarded to us.
  */
 static void
-xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg)
+xpnet_receive(short partid, int channel, struct xpnet_message *msg)
 {
 	struct sk_buff *skb;
 	bte_result_t bret;
@@ -282,7 +282,7 @@
  * state or message reception on a connection.
  */
 static void
-xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel,
+xpnet_connection_activity(enum xp_retval reason, short partid, int channel,
 			  void *data, void *key)
 {
 	long bp;
@@ -291,13 +291,13 @@
 	DBUG_ON(channel != XPC_NET_CHANNEL);
 
 	switch (reason) {
-	case xpcMsgReceived:	/* message received */
+	case xpMsgReceived:	/* message received */
 		DBUG_ON(data == NULL);
 
 		xpnet_receive(partid, channel, (struct xpnet_message *)data);
 		break;
 
-	case xpcConnected:	/* connection completed to a partition */
+	case xpConnected:	/* connection completed to a partition */
 		spin_lock_bh(&xpnet_broadcast_lock);
 		xpnet_broadcast_partitions |= 1UL << (partid - 1);
 		bp = xpnet_broadcast_partitions;
@@ -330,7 +330,7 @@
 static int
 xpnet_dev_open(struct net_device *dev)
 {
-	enum xpc_retval ret;
+	enum xp_retval ret;
 
 	dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, "
 		"%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity,
@@ -340,7 +340,7 @@
 	ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL,
 			  XPNET_MSG_SIZE, XPNET_MSG_NENTRIES,
 			  XPNET_MAX_KTHREADS, XPNET_MAX_IDLE_KTHREADS);
-	if (ret != xpcSuccess) {
+	if (ret != xpSuccess) {
 		dev_err(xpnet, "ifconfig up of %s failed on XPC connect, "
 			"ret=%d\n", dev->name, ret);
 
@@ -407,7 +407,7 @@
  * release the skb and then release our pending message structure.
  */
 static void
-xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel,
+xpnet_send_completed(enum xp_retval reason, short partid, int channel,
 		     void *__qm)
 {
 	struct xpnet_pending_msg *queued_msg = (struct xpnet_pending_msg *)__qm;
@@ -439,12 +439,12 @@
 xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct xpnet_pending_msg *queued_msg;
-	enum xpc_retval ret;
+	enum xp_retval ret;
 	struct xpnet_message *msg;
 	u64 start_addr, end_addr;
 	long dp;
 	u8 second_mac_octet;
-	partid_t dest_partid;
+	short dest_partid;
 	struct xpnet_dev_private *priv;
 	u16 embedded_bytes;
 
@@ -528,7 +528,7 @@
 
 		ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL,
 				   XPC_NOWAIT, (void **)&msg);
-		if (unlikely(ret != xpcSuccess))
+		if (unlikely(ret != xpSuccess))
 			continue;
 
 		msg->embedded_bytes = embedded_bytes;
@@ -557,7 +557,7 @@
 
 		ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg,
 				      xpnet_send_completed, queued_msg);
-		if (unlikely(ret != xpcSuccess)) {
+		if (unlikely(ret != xpSuccess)) {
 			atomic_dec(&queued_msg->use_count);
 			continue;
 		}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7fb02e1..299118d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -187,7 +187,7 @@
 	struct mmc_request	*mrq;		/* Current request */
 	struct mmc_command	*cmd;		/* Current command */
 	struct mmc_data		*data;		/* Current data request */
-	int			data_early:1;	/* Data finished before cmd */
+	unsigned int		data_early:1;	/* Data finished before cmd */
 
 	struct scatterlist	*cur_sg;	/* We're working on this */
 	int			num_sg;		/* Entries left */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d27f54a..9f6cc8a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2426,7 +2426,7 @@
 
 config EHEA
 	tristate "eHEA Ethernet support"
-	depends on IBMEBUS && INET && SPARSEMEM
+	depends on IBMEBUS && INET && SPARSEMEM && MEMORY_HOTPLUG
 	select INET_LRO
 	---help---
 	  This driver supports the IBM pSeries eHEA ethernet adapter.
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 0afe522..9c2394d 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1,7 +1,7 @@
 /*
  * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
  * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
  *
  * Derived from Intel e1000 driver
  * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
@@ -36,7 +36,6 @@
  * A very incomplete list of things that need to be dealt with:
  *
  * TODO:
- * Wake on LAN.
  * Add more ethtool functions.
  * Fix abstruse irq enable/disable condition described here:
  *	http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
@@ -638,21 +637,18 @@
 }
 
 /*
- *TODO: do something or get rid of this
+ * Force the PHY into power saving mode using vendor magic.
  */
 #ifdef CONFIG_PM
-static s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+static void atl1_phy_enter_power_saving(struct atl1_hw *hw)
 {
-/*    s32 ret_val;
- *    u16 phy_data;
- */
+	atl1_write_phy_reg(hw, MII_DBG_ADDR, 0);
+	atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E);
+	atl1_write_phy_reg(hw, MII_DBG_ADDR, 2);
+	atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000);
+	atl1_write_phy_reg(hw, MII_DBG_ADDR, 3);
+	atl1_write_phy_reg(hw, MII_DBG_DATA, 0);
 
-/*
-    ret_val = atl1_write_phy_reg(hw, ...);
-    ret_val = atl1_write_phy_reg(hw, ...);
-    ....
-*/
-	return 0;
 }
 #endif
 
@@ -2784,64 +2780,93 @@
 	struct atl1_hw *hw = &adapter->hw;
 	u32 ctrl = 0;
 	u32 wufc = adapter->wol;
+	u32 val;
+	int retval;
+	u16 speed;
+	u16 duplex;
 
 	netif_device_detach(netdev);
 	if (netif_running(netdev))
 		atl1_down(adapter);
 
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+
 	atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
 	atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
-	if (ctrl & BMSR_LSTATUS)
+	val = ctrl & BMSR_LSTATUS;
+	if (val)
 		wufc &= ~ATLX_WUFC_LNKC;
 
-	/* reduce speed to 10/100M */
-	if (wufc) {
-		atl1_phy_enter_power_saving(hw);
-		/* if resume, let driver to re- setup link */
-		hw->phy_configured = false;
-		atl1_set_mac_addr(hw);
-		atlx_set_multi(netdev);
+	if (val && wufc) {
+		val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+		if (val) {
+			if (netif_msg_ifdown(adapter))
+				dev_printk(KERN_DEBUG, &pdev->dev,
+					"error getting speed/duplex\n");
+			goto disable_wol;
+		}
 
 		ctrl = 0;
-		/* turn on magic packet wol */
+
+		/* enable magic packet WOL */
 		if (wufc & ATLX_WUFC_MAG)
-			ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
-
-		/* turn on Link change WOL */
-		if (wufc & ATLX_WUFC_LNKC)
-			ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+			ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN);
 		iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+		ioread32(hw->hw_addr + REG_WOL_CTRL);
 
-		/* turn on all-multi mode if wake on multicast is enabled */
-		ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
-		ctrl &= ~MAC_CTRL_DBG;
-		ctrl &= ~MAC_CTRL_PROMIS_EN;
-		if (wufc & ATLX_WUFC_MC)
-			ctrl |= MAC_CTRL_MC_ALL_EN;
-		else
-			ctrl &= ~MAC_CTRL_MC_ALL_EN;
-
-		/* turn on broadcast mode if wake on-BC is enabled */
-		if (wufc & ATLX_WUFC_BC)
+		/* configure the mac */
+		ctrl = MAC_CTRL_RX_EN;
+		ctrl |= ((u32)((speed == SPEED_1000) ? MAC_CTRL_SPEED_1000 :
+			MAC_CTRL_SPEED_10_100) << MAC_CTRL_SPEED_SHIFT);
+		if (duplex == FULL_DUPLEX)
+			ctrl |= MAC_CTRL_DUPLX;
+		ctrl |= (((u32)adapter->hw.preamble_len &
+			MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+		if (adapter->vlgrp)
+			ctrl |= MAC_CTRL_RMV_VLAN;
+		if (wufc & ATLX_WUFC_MAG)
 			ctrl |= MAC_CTRL_BC_EN;
-		else
-			ctrl &= ~MAC_CTRL_BC_EN;
-
-		/* enable RX */
-		ctrl |= MAC_CTRL_RX_EN;
 		iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
-		pci_enable_wake(pdev, PCI_D3hot, 1);
-		pci_enable_wake(pdev, PCI_D3cold, 1);
-	} else {
-		iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
-		pci_enable_wake(pdev, PCI_D3hot, 0);
-		pci_enable_wake(pdev, PCI_D3cold, 0);
+		ioread32(hw->hw_addr + REG_MAC_CTRL);
+
+		/* poke the PHY */
+		ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+		iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC);
+		ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+		goto exit;
 	}
 
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
+	if (!val && wufc) {
+		ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+		iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+		ioread32(hw->hw_addr + REG_WOL_CTRL);
+		iowrite32(0, hw->hw_addr + REG_MAC_CTRL);
+		ioread32(hw->hw_addr + REG_MAC_CTRL);
+		hw->phy_configured = false;
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+		goto exit;
+	}
 
-	pci_set_power_state(pdev, PCI_D3hot);
+disable_wol:
+	iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+	ioread32(hw->hw_addr + REG_WOL_CTRL);
+	ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+	iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC);
+	ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+	atl1_phy_enter_power_saving(hw);
+	hw->phy_configured = false;
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+exit:
+	if (netif_running(netdev))
+		pci_disable_msi(adapter->pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
 	return 0;
 }
@@ -2855,20 +2880,26 @@
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
-	/* FIXME: check and handle */
 	err = pci_enable_device(pdev);
+	if (err) {
+		if (netif_msg_ifup(adapter))
+			dev_printk(KERN_DEBUG, &pdev->dev,
+				"error enabling pci device\n");
+		return err;
+	}
+
+	pci_set_master(pdev);
+	iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
 	pci_enable_wake(pdev, PCI_D3hot, 0);
 	pci_enable_wake(pdev, PCI_D3cold, 0);
 
-	iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
-	atl1_reset(adapter);
+	atl1_reset_hw(&adapter->hw);
+	adapter->cmb.cmb->int_stats = 0;
 
 	if (netif_running(netdev))
 		atl1_up(adapter);
 	netif_device_attach(netdev);
 
-	atl1_via_workaround(adapter);
-
 	return 0;
 }
 #else
@@ -2876,6 +2907,13 @@
 #define atl1_resume NULL
 #endif
 
+static void atl1_shutdown(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PM
+	atl1_suspend(pdev, PMSG_SUSPEND);
+#endif
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void atl1_poll_controller(struct net_device *netdev)
 {
@@ -3122,7 +3160,8 @@
 	.probe = atl1_probe,
 	.remove = __devexit_p(atl1_remove),
 	.suspend = atl1_suspend,
-	.resume = atl1_resume
+	.resume = atl1_resume,
+	.shutdown = atl1_shutdown
 };
 
 /*
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 51893d6..a5015b1 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -1,7 +1,7 @@
 /*
  * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
  * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
  *
  * Derived from Intel e1000 driver
  * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index f06b854..b3e7fcf 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -2,7 +2,7 @@
  *
  * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
  * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
  * Copyright(c) 2007 Atheros Corporation. All rights reserved.
  *
  * Derived from Intel e1000 driver
diff --git a/drivers/net/atlx/atlx.h b/drivers/net/atlx/atlx.h
index 3be7c09..297a03d 100644
--- a/drivers/net/atlx/atlx.h
+++ b/drivers/net/atlx/atlx.h
@@ -2,7 +2,7 @@
  *
  * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
  * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
  * Copyright(c) 2007 Atheros Corporation. All rights reserved.
  *
  * Derived from Intel e1000 driver
@@ -29,7 +29,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 
-#define ATLX_DRIVER_VERSION "2.1.1"
+#define ATLX_DRIVER_VERSION "2.1.3"
 MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \
 	Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
 MODULE_LICENSE("GPL");
@@ -460,6 +460,9 @@
 #define MII_ATLX_PSSR_100MBS		0x4000	/* 01=100Mbs */
 #define MII_ATLX_PSSR_1000MBS		0x8000	/* 10=1000Mbs */
 
+#define MII_DBG_ADDR			0x1D
+#define MII_DBG_DATA			0x1E
+
 /* PCI Command Register Bit Definitions */
 #define PCI_REG_COMMAND			0x04	/* PCI Command Register */
 #define CMD_IO_SPACE			0x0001
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 4fdb13f..acebe43 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -71,6 +71,7 @@
 	USING_MSIX = (1 << 2),
 	QUEUES_BOUND = (1 << 3),
 	TP_PARITY_INIT = (1 << 4),
+	NAPI_INIT = (1 << 5),
 };
 
 struct fl_pg_chunk {
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 91ee727..579bee4 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -698,6 +698,7 @@
 void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
 int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
 		    int reset);
+int t3_replay_prep_adapter(struct adapter *adapter);
 void t3_led_ready(struct adapter *adapter);
 void t3_fatal_err(struct adapter *adapter);
 void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index ce949d5..3a31272 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -421,6 +421,13 @@
 			netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
 				       64);
 	}
+
+	/*
+	 * netif_napi_add() can be called only once per napi_struct because it
+	 * adds each new napi_struct to a list.  Be careful not to call it a
+	 * second time, e.g., during EEH recovery, by making a note of it.
+	 */
+	adap->flags |= NAPI_INIT;
 }
 
 /*
@@ -896,7 +903,8 @@
 			goto out;
 
 		setup_rss(adap);
-		init_napi(adap);
+		if (!(adap->flags & NAPI_INIT))
+			init_napi(adap);
 		adap->flags |= FULL_INIT_DONE;
 	}
 
@@ -999,7 +1007,7 @@
 		return 0;
 
 	if (!adap_up && (err = cxgb_up(adapter)) < 0)
-		return err;
+		goto out;
 
 	t3_tp_set_offload_mode(adapter, 1);
 	tdev->lldev = adapter->port[0];
@@ -1061,10 +1069,8 @@
 	int other_ports = adapter->open_device_map & PORT_MASK;
 	int err;
 
-	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
-		quiesce_rx(adapter);
+	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
 		return err;
-	}
 
 	set_bit(pi->port_id, &adapter->open_device_map);
 	if (is_offload(adapter) && !ofld_disable) {
@@ -2424,14 +2430,11 @@
 	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
 		offload_close(&adapter->tdev);
 
-	/* Free sge resources */
-	t3_free_sge_resources(adapter);
-
 	adapter->flags &= ~FULL_INIT_DONE;
 
 	pci_disable_device(pdev);
 
-	/* Request a slot slot reset. */
+	/* Request a slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 
@@ -2448,13 +2451,20 @@
 	if (pci_enable_device(pdev)) {
 		dev_err(&pdev->dev,
 			"Cannot re-enable PCI device after reset.\n");
-		return PCI_ERS_RESULT_DISCONNECT;
+		goto err;
 	}
 	pci_set_master(pdev);
+	pci_restore_state(pdev);
 
-	t3_prep_adapter(adapter, adapter->params.info, 1);
+	/* Free sge resources */
+	t3_free_sge_resources(adapter);
+
+	if (t3_replay_prep_adapter(adapter))
+		goto err;
 
 	return PCI_ERS_RESULT_RECOVERED;
+err:
+	return PCI_ERS_RESULT_DISCONNECT;
 }
 
 /**
@@ -2483,13 +2493,6 @@
 			netif_device_attach(netdev);
 		}
 	}
-
-	if (is_offload(adapter)) {
-		__set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
-		if (offload_open(adapter->port[0]))
-			printk(KERN_WARNING
-			       "Could not bring back offload capabilities\n");
-	}
 }
 
 static struct pci_error_handlers t3_err_handler = {
@@ -2608,6 +2611,7 @@
 	}
 
 	pci_set_master(pdev);
+	pci_save_state(pdev);
 
 	mmio_start = pci_resource_start(pdev, 0);
 	mmio_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 02dbbb3..5671788 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -444,6 +444,14 @@
 
 #define A_PCIE_CFG 0x88
 
+#define S_ENABLELINKDWNDRST    21
+#define V_ENABLELINKDWNDRST(x) ((x) << S_ENABLELINKDWNDRST)
+#define F_ENABLELINKDWNDRST    V_ENABLELINKDWNDRST(1U)
+
+#define S_ENABLELINKDOWNRST    20
+#define V_ENABLELINKDOWNRST(x) ((x) << S_ENABLELINKDOWNRST)
+#define F_ENABLELINKDOWNRST    V_ENABLELINKDOWNRST(1U)
+
 #define S_PCIE_CLIDECEN    16
 #define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
 #define F_PCIE_CLIDECEN    V_PCIE_CLIDECEN(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 98a6bbd..796eb30 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -539,6 +539,31 @@
 }
 
 /**
+ *	t3_reset_qset - reset a sge qset
+ *	@q: the queue set
+ *
+ *	Reset the qset structure.
+ *	the NAPI structure is preserved in the event of
+ *	the qset's reincarnation, for example during EEH recovery.
+ */
+static void t3_reset_qset(struct sge_qset *q)
+{
+	if (q->adap &&
+	    !(q->adap->flags & NAPI_INIT)) {
+		memset(q, 0, sizeof(*q));
+		return;
+	}
+
+	q->adap = NULL;
+	memset(&q->rspq, 0, sizeof(q->rspq));
+	memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET);
+	memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
+	q->txq_stopped = 0;
+	memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
+}
+
+
+/**
  *	free_qset - free the resources of an SGE queue set
  *	@adapter: the adapter owning the queue set
  *	@q: the queue set
@@ -594,7 +619,7 @@
 				  q->rspq.desc, q->rspq.phys_addr);
 	}
 
-	memset(q, 0, sizeof(*q));
+	t3_reset_qset(q);
 }
 
 /**
@@ -1365,7 +1390,7 @@
  */
 int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
 {
-	int ret; 
+	int ret;
 	local_bh_disable();
 	ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
 	local_bh_enable();
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index a99496a..d405a93 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -3264,6 +3264,7 @@
 
 	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
 	t3_set_reg_field(adap, A_PCIE_CFG, 0,
+			 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
 			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
 }
 
@@ -3655,3 +3656,30 @@
 	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
 			 F_GPIO0_OUT_VAL);
 }
+
+int t3_replay_prep_adapter(struct adapter *adapter)
+{
+	const struct adapter_info *ai = adapter->params.info;
+	unsigned int i, j = 0;
+	int ret;
+
+	early_hw_init(adapter, ai);
+	ret = init_parity(adapter);
+	if (ret)
+		return ret;
+
+	for_each_port(adapter, i) {
+		struct port_info *p = adap2pinfo(adapter, i);
+		while (!adapter->params.vpd.port_type[j])
+			++j;
+
+		p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+					ai->mdio_ops);
+
+		p->phy.ops->power_down(&p->phy, 1);
+		++j;
+	}
+
+return 0;
+}
+
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index e6fe261..d45bcd2 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -117,6 +117,9 @@
 
 	struct mutex	 addr_lock;	/* phy and eeprom access lock */
 
+	struct delayed_work phy_poll;
+	struct net_device  *ndev;
+
 	spinlock_t lock;
 
 	struct mii_if_info mii;
@@ -297,6 +300,10 @@
 	}
 }
 
+static void dm9000_schedule_poll(board_info_t *db)
+{
+	schedule_delayed_work(&db->phy_poll, HZ * 2);
+}
 
 /* Our watchdog timed out. Called by the networking layer */
 static void dm9000_timeout(struct net_device *dev)
@@ -465,6 +472,17 @@
  	.set_eeprom		= dm9000_set_eeprom,
 };
 
+static void
+dm9000_poll_work(struct work_struct *w)
+{
+	struct delayed_work *dw = container_of(w, struct delayed_work, work);
+	board_info_t *db = container_of(dw, board_info_t, phy_poll);
+
+	mii_check_media(&db->mii, netif_msg_link(db), 0);
+	
+	if (netif_running(db->ndev))
+		dm9000_schedule_poll(db);
+}
 
 /* dm9000_release_board
  *
@@ -503,7 +521,7 @@
 /*
  * Search DM9000 board, allocate space and register it
  */
-static int
+static int __devinit
 dm9000_probe(struct platform_device *pdev)
 {
 	struct dm9000_plat_data *pdata = pdev->dev.platform_data;
@@ -525,17 +543,21 @@
 
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
-	dev_dbg(&pdev->dev, "dm9000_probe()");
+	dev_dbg(&pdev->dev, "dm9000_probe()\n");
 
 	/* setup board info structure */
 	db = (struct board_info *) ndev->priv;
 	memset(db, 0, sizeof (*db));
 
 	db->dev = &pdev->dev;
+	db->ndev = ndev;
 
 	spin_lock_init(&db->lock);
 	mutex_init(&db->addr_lock);
 
+	INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
+
+
 	if (pdev->num_resources < 2) {
 		ret = -ENODEV;
 		goto out;
@@ -761,6 +783,8 @@
 
 	mii_check_media(&db->mii, netif_msg_link(db), 1);
 	netif_start_queue(dev);
+	
+	dm9000_schedule_poll(db);
 
 	return 0;
 }
@@ -879,6 +903,8 @@
 	if (netif_msg_ifdown(db))
 		dev_dbg(db->dev, "shutting down %s\n", ndev->name);
 
+	cancel_delayed_work(&db->phy_poll);
+
 	netif_stop_queue(ndev);
 	netif_carrier_off(ndev);
 
@@ -1288,6 +1314,8 @@
 	spin_unlock_irqrestore(&db->lock,flags);
 
 	mutex_unlock(&db->addr_lock);
+
+	dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
 	return ret;
 }
 
@@ -1301,6 +1329,7 @@
 	unsigned long flags;
 	unsigned long reg_save;
 
+	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
 	mutex_lock(&db->addr_lock);
 
 	spin_lock_irqsave(&db->lock,flags);
@@ -1372,7 +1401,7 @@
 	return 0;
 }
 
-static int
+static int __devexit
 dm9000_drv_remove(struct platform_device *pdev)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
@@ -1393,7 +1422,7 @@
 		.owner	 = THIS_MODULE,
 	},
 	.probe   = dm9000_probe,
-	.remove  = dm9000_drv_remove,
+	.remove  = __devexit_p(dm9000_drv_remove),
 	.suspend = dm9000_drv_suspend,
 	.resume  = dm9000_drv_resume,
 };
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index f5dacce..fe872fb 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0090"
+#define DRV_VERSION	"EHEA_0091"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
@@ -118,6 +118,13 @@
 #define EHEA_MR_ACC_CTRL       0x00800000
 
 #define EHEA_BUSMAP_START      0x8000000000000000ULL
+#define EHEA_INVAL_ADDR        0xFFFFFFFFFFFFFFFFULL
+#define EHEA_DIR_INDEX_SHIFT 13                   /* 8k Entries in 64k block */
+#define EHEA_TOP_INDEX_SHIFT (EHEA_DIR_INDEX_SHIFT * 2)
+#define EHEA_MAP_ENTRIES (1 << EHEA_DIR_INDEX_SHIFT)
+#define EHEA_MAP_SIZE (0x10000)                   /* currently fixed map size */
+#define EHEA_INDEX_MASK (EHEA_MAP_ENTRIES - 1)
+
 
 #define EHEA_WATCH_DOG_TIMEOUT 10*HZ
 
@@ -192,10 +199,20 @@
 				   set to 0 if unused */
 };
 
-struct ehea_busmap {
-	unsigned int entries;		/* total number of entries */
-	unsigned int valid_sections;	/* number of valid sections */
-	u64 *vaddr;
+/*
+ * Memory map data structures
+ */
+struct ehea_dir_bmap
+{
+	u64 ent[EHEA_MAP_ENTRIES];
+};
+struct ehea_top_bmap
+{
+	struct ehea_dir_bmap *dir[EHEA_MAP_ENTRIES];
+};
+struct ehea_bmap
+{
+	struct ehea_top_bmap *top[EHEA_MAP_ENTRIES];
 };
 
 struct ehea_qp;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index f9bc21c..d1b6d4e 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -35,6 +35,7 @@
 #include <linux/if_ether.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <linux/memory.h>
 #include <asm/kexec.h>
 #include <linux/mutex.h>
 
@@ -3503,6 +3504,24 @@
 					      0, H_DEREG_BCMC);
 }
 
+static int ehea_mem_notifier(struct notifier_block *nb,
+                             unsigned long action, void *data)
+{
+	switch (action) {
+	case MEM_OFFLINE:
+		ehea_info("memory has been removed");
+		ehea_rereg_mrs(NULL);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ehea_mem_nb = {
+	.notifier_call = ehea_mem_notifier,
+};
+
 static int ehea_reboot_notifier(struct notifier_block *nb,
 				unsigned long action, void *unused)
 {
@@ -3581,6 +3600,10 @@
 	if (ret)
 		ehea_info("failed registering reboot notifier");
 
+	ret = register_memory_notifier(&ehea_mem_nb);
+	if (ret)
+		ehea_info("failed registering memory remove notifier");
+
 	ret = crash_shutdown_register(&ehea_crash_handler);
 	if (ret)
 		ehea_info("failed registering crash handler");
@@ -3604,6 +3627,7 @@
 out3:
 	ibmebus_unregister_driver(&ehea_driver);
 out2:
+	unregister_memory_notifier(&ehea_mem_nb);
 	unregister_reboot_notifier(&ehea_reboot_nb);
 	crash_shutdown_unregister(&ehea_crash_handler);
 out:
@@ -3621,6 +3645,7 @@
 	ret = crash_shutdown_unregister(&ehea_crash_handler);
 	if (ret)
 		ehea_info("failed unregistering crash handler");
+	unregister_memory_notifier(&ehea_mem_nb);
 	kfree(ehea_fw_handles.arr);
 	kfree(ehea_bcmc_regs.arr);
 	ehea_destroy_busmap();
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index d522e90..140f05b 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -31,8 +31,8 @@
 #include "ehea_phyp.h"
 #include "ehea_qmr.h"
 
+struct ehea_bmap *ehea_bmap = NULL;
 
-struct ehea_busmap ehea_bmap = { 0, 0, NULL };
 
 
 static void *hw_qpageit_get_inc(struct hw_queue *queue)
@@ -559,125 +559,253 @@
 	return 0;
 }
 
-int ehea_create_busmap(void)
+static inline int ehea_calc_index(unsigned long i, unsigned long s)
 {
-	u64 vaddr = EHEA_BUSMAP_START;
-	unsigned long high_section_index = 0;
-	int i;
+	return (i >> s) & EHEA_INDEX_MASK;
+}
 
-	/*
-	 * Sections are not in ascending order -> Loop over all sections and
-	 * find the highest PFN to compute the required map size.
-	*/
-	ehea_bmap.valid_sections = 0;
+static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap,
+				     int dir)
+{
+	if(!ehea_top_bmap->dir[dir]) {
+		ehea_top_bmap->dir[dir] =
+			kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL);
+		if (!ehea_top_bmap->dir[dir])
+			return -ENOMEM;
+	}
+	return 0;
+}
 
-	for (i = 0; i < NR_MEM_SECTIONS; i++)
-		if (valid_section_nr(i))
-			high_section_index = i;
+static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir)
+{
+	if(!ehea_bmap->top[top]) {
+		ehea_bmap->top[top] =
+			kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL);
+		if (!ehea_bmap->top[top])
+			return -ENOMEM;
+	}
+	return ehea_init_top_bmap(ehea_bmap->top[top], dir);
+}
 
-	ehea_bmap.entries = high_section_index + 1;
-	ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
+static int ehea_create_busmap_callback(unsigned long pfn,
+				       unsigned long nr_pages, void *arg)
+{
+	unsigned long i, mr_len, start_section, end_section;
+	start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE;
+	end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
+	mr_len = *(unsigned long *)arg;
 
-	if (!ehea_bmap.vaddr)
+	ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
+	if (!ehea_bmap)
 		return -ENOMEM;
 
-	for (i = 0 ; i < ehea_bmap.entries; i++) {
-		unsigned long pfn = section_nr_to_pfn(i);
+	for (i = start_section; i < end_section; i++) {
+		int ret;
+		int top, dir, idx;
+		u64 vaddr;
 
-		if (pfn_valid(pfn)) {
-			ehea_bmap.vaddr[i] = vaddr;
-			vaddr += EHEA_SECTSIZE;
-			ehea_bmap.valid_sections++;
-		} else
-			ehea_bmap.vaddr[i] = 0;
+		top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
+		dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
+
+		ret = ehea_init_bmap(ehea_bmap, top, dir);
+		if(ret)
+			return ret;
+
+		idx = i & EHEA_INDEX_MASK;
+		vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE;
+
+		ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr;
 	}
 
+	mr_len += nr_pages * PAGE_SIZE;
+	*(unsigned long *)arg = mr_len;
+
 	return 0;
 }
 
+static unsigned long ehea_mr_len;
+
+static DEFINE_MUTEX(ehea_busmap_mutex);
+
+int ehea_create_busmap(void)
+{
+	int ret;
+	mutex_lock(&ehea_busmap_mutex);
+	ehea_mr_len = 0;
+	ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len,
+				   ehea_create_busmap_callback);
+	mutex_unlock(&ehea_busmap_mutex);
+	return ret;
+}
+
 void ehea_destroy_busmap(void)
 {
-	vfree(ehea_bmap.vaddr);
+	int top, dir;
+	mutex_lock(&ehea_busmap_mutex);
+	if (!ehea_bmap)
+		goto out_destroy;
+
+	for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
+		if (!ehea_bmap->top[top])
+			continue;
+
+		for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
+			if (!ehea_bmap->top[top]->dir[dir])
+				continue;
+
+			kfree(ehea_bmap->top[top]->dir[dir]);
+		}
+
+		kfree(ehea_bmap->top[top]);
+	}
+
+	kfree(ehea_bmap);
+	ehea_bmap = NULL;
+out_destroy:	
+	mutex_unlock(&ehea_busmap_mutex);
 }
 
 u64 ehea_map_vaddr(void *caddr)
 {
-	u64 mapped_addr;
-	unsigned long index = __pa(caddr) >> SECTION_SIZE_BITS;
+	int top, dir, idx;
+	unsigned long index, offset;
 
-	if (likely(index < ehea_bmap.entries)) {
-		mapped_addr = ehea_bmap.vaddr[index];
-		if (likely(mapped_addr))
-			mapped_addr |= (((unsigned long)caddr)
-					& (EHEA_SECTSIZE - 1));
-		else
-			mapped_addr = -1;
-	} else
-		mapped_addr = -1;
+	if (!ehea_bmap)
+		return EHEA_INVAL_ADDR;
 
-	if (unlikely(mapped_addr == -1))
-		if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
-			schedule_work(&ehea_rereg_mr_task);
+	index = virt_to_abs(caddr) >> SECTION_SIZE_BITS;
+	top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
+	if (!ehea_bmap->top[top])
+		return EHEA_INVAL_ADDR;
 
-	return mapped_addr;
+	dir = (index >> EHEA_DIR_INDEX_SHIFT) & EHEA_INDEX_MASK;
+	if (!ehea_bmap->top[top]->dir[dir])
+		return EHEA_INVAL_ADDR;
+
+	idx = index & EHEA_INDEX_MASK;
+	if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
+		return EHEA_INVAL_ADDR;
+
+	offset = (unsigned long)caddr & (EHEA_SECTSIZE - 1);
+	return ehea_bmap->top[top]->dir[dir]->ent[idx] | offset;
+}
+
+static inline void *ehea_calc_sectbase(int top, int dir, int idx)
+{
+	unsigned long ret = idx;
+	ret |= dir << EHEA_DIR_INDEX_SHIFT;
+	ret |= top << EHEA_TOP_INDEX_SHIFT;
+	return abs_to_virt(ret << SECTION_SIZE_BITS);
+}
+
+static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
+			       struct ehea_adapter *adapter,
+			       struct ehea_mr *mr)
+{
+	void *pg;
+	u64 j, m, hret;
+	unsigned long k = 0;
+	u64 pt_abs = virt_to_abs(pt);
+
+	void *sectbase = ehea_calc_sectbase(top, dir, idx);
+
+	for (j = 0; j < (EHEA_PAGES_PER_SECTION / EHEA_MAX_RPAGE); j++) {
+
+		for (m = 0; m < EHEA_MAX_RPAGE; m++) {
+			pg = sectbase + ((k++) * EHEA_PAGESIZE);
+			pt[m] = virt_to_abs(pg);
+		}
+		hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
+						0, pt_abs, EHEA_MAX_RPAGE);
+
+		if ((hret != H_SUCCESS)
+		    && (hret != H_PAGE_REGISTERED)) {
+			ehea_h_free_resource(adapter->handle, mr->handle,
+					     FORCE_FREE);
+			ehea_error("register_rpage_mr failed");
+			return hret;
+		}
+	}
+	return hret;
+}
+
+static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
+				struct ehea_adapter *adapter,
+				struct ehea_mr *mr)
+{
+	u64 hret = H_SUCCESS;
+	int idx;
+
+	for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
+		if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
+			continue;
+		
+		hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
+		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+			    	return hret;
+	}
+	return hret;
+}
+
+static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
+				    struct ehea_adapter *adapter,
+				    struct ehea_mr *mr)
+{
+	u64 hret = H_SUCCESS;
+	int dir;
+
+	for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
+		if (!ehea_bmap->top[top]->dir[dir])
+			continue;
+
+		hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
+		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+			    	return hret;
+	}
+	return hret;
 }
 
 int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
 {
 	int ret;
 	u64 *pt;
-	void *pg;
-	u64 hret, pt_abs, i, j, m, mr_len;
+	u64 hret;
 	u32 acc_ctrl = EHEA_MR_ACC_CTRL;
 
-	mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
+	unsigned long top;
 
-	pt =  kzalloc(PAGE_SIZE, GFP_KERNEL);
+	pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!pt) {
 		ehea_error("no mem");
 		ret = -ENOMEM;
 		goto out;
 	}
-	pt_abs = virt_to_abs(pt);
 
-	hret = ehea_h_alloc_resource_mr(adapter->handle,
-					EHEA_BUSMAP_START, mr_len,
-					acc_ctrl, adapter->pd,
+	hret = ehea_h_alloc_resource_mr(adapter->handle, EHEA_BUSMAP_START,
+					ehea_mr_len, acc_ctrl, adapter->pd,
 					&mr->handle, &mr->lkey);
+
 	if (hret != H_SUCCESS) {
 		ehea_error("alloc_resource_mr failed");
 		ret = -EIO;
 		goto out;
 	}
 
-	for (i = 0 ; i < ehea_bmap.entries; i++)
-		if (ehea_bmap.vaddr[i]) {
-			void *sectbase = __va(i << SECTION_SIZE_BITS);
-			unsigned long k = 0;
+	if (!ehea_bmap) {
+		ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
+		ehea_error("no busmap available");
+		ret = -EIO;
+		goto out;
+	}
 
-			for (j = 0; j < (EHEA_PAGES_PER_SECTION /
-					 EHEA_MAX_RPAGE); j++) {
+	for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
+		if (!ehea_bmap->top[top])
+			continue;
 
-				for (m = 0; m < EHEA_MAX_RPAGE; m++) {
-					pg = sectbase + ((k++) * EHEA_PAGESIZE);
-					pt[m] = virt_to_abs(pg);
-				}
-
-				hret = ehea_h_register_rpage_mr(adapter->handle,
-								mr->handle,
-								0, 0, pt_abs,
-								EHEA_MAX_RPAGE);
-				if ((hret != H_SUCCESS)
-				    && (hret != H_PAGE_REGISTERED)) {
-					ehea_h_free_resource(adapter->handle,
-							     mr->handle,
-							     FORCE_FREE);
-					ehea_error("register_rpage_mr failed");
-					ret = -EIO;
-					goto out;
-				}
-			}
-		}
+		hret = ehea_reg_mr_dir_sections(top, pt, adapter, mr);
+		if((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
+			break;
+	}
 
 	if (hret != H_SUCCESS) {
 		ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6f22f06..25bdd08 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -635,6 +635,8 @@
 			dev_kfree_skb_any(priv->tx_skbuff[i]);
 			priv->tx_skbuff[i] = NULL;
 		}
+
+		txbdp++;
 	}
 
 	kfree(priv->tx_skbuff);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index ef63c8d..c91b12e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -144,11 +144,13 @@
 	char *req_bytes;
 	struct myri10ge_tx_buffer_state *info;
 	int mask;		/* number of transmit slots -1  */
-	int boundary;		/* boundary transmits cannot cross */
 	int req ____cacheline_aligned;	/* transmit slots submitted     */
 	int pkt_start;		/* packets started */
+	int stop_queue;
+	int linearized;
 	int done ____cacheline_aligned;	/* transmit slots completed     */
 	int pkt_done;		/* packets completed */
+	int wake_queue;
 };
 
 struct myri10ge_rx_done {
@@ -160,29 +162,50 @@
 	struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
 };
 
-struct myri10ge_priv {
-	int running;		/* running?             */
-	int csum_flag;		/* rx_csums?            */
+struct myri10ge_slice_netstats {
+	unsigned long rx_packets;
+	unsigned long tx_packets;
+	unsigned long rx_bytes;
+	unsigned long tx_bytes;
+	unsigned long rx_dropped;
+	unsigned long tx_dropped;
+};
+
+struct myri10ge_slice_state {
 	struct myri10ge_tx_buf tx;	/* transmit ring        */
 	struct myri10ge_rx_buf rx_small;
 	struct myri10ge_rx_buf rx_big;
 	struct myri10ge_rx_done rx_done;
-	int small_bytes;
-	int big_bytes;
 	struct net_device *dev;
 	struct napi_struct napi;
+	struct myri10ge_priv *mgp;
+	struct myri10ge_slice_netstats stats;
+	__be32 __iomem *irq_claim;
+	struct mcp_irq_data *fw_stats;
+	dma_addr_t fw_stats_bus;
+	int watchdog_tx_done;
+	int watchdog_tx_req;
+};
+
+struct myri10ge_priv {
+	struct myri10ge_slice_state ss;
+	int tx_boundary;	/* boundary transmits cannot cross */
+	int running;		/* running?             */
+	int csum_flag;		/* rx_csums?            */
+	int small_bytes;
+	int big_bytes;
+	int max_intr_slots;
+	struct net_device *dev;
 	struct net_device_stats stats;
+	spinlock_t stats_lock;
 	u8 __iomem *sram;
 	int sram_size;
 	unsigned long board_span;
 	unsigned long iomem_base;
-	__be32 __iomem *irq_claim;
 	__be32 __iomem *irq_deassert;
 	char *mac_addr_string;
 	struct mcp_cmd_response *cmd;
 	dma_addr_t cmd_bus;
-	struct mcp_irq_data *fw_stats;
-	dma_addr_t fw_stats_bus;
 	struct pci_dev *pdev;
 	int msi_enabled;
 	u32 link_state;
@@ -191,20 +214,16 @@
 	__be32 __iomem *intr_coal_delay_ptr;
 	int mtrr;
 	int wc_enabled;
-	int wake_queue;
-	int stop_queue;
 	int down_cnt;
 	wait_queue_head_t down_wq;
 	struct work_struct watchdog_work;
 	struct timer_list watchdog_timer;
-	int watchdog_tx_done;
-	int watchdog_tx_req;
-	int watchdog_pause;
 	int watchdog_resets;
-	int tx_linearized;
+	int watchdog_pause;
 	int pause;
 	char *fw_name;
 	char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
+	char *product_code_string;
 	char fw_version[128];
 	int fw_ver_major;
 	int fw_ver_minor;
@@ -228,58 +247,54 @@
 
 static char *myri10ge_fw_name = NULL;
 module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name\n");
+MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
 
 static int myri10ge_ecrc_enable = 1;
 module_param(myri10ge_ecrc_enable, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E\n");
-
-static int myri10ge_max_intr_slots = 1024;
-module_param(myri10ge_max_intr_slots, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_max_intr_slots, "Interrupt queue slots\n");
+MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E");
 
 static int myri10ge_small_bytes = -1;	/* -1 == auto */
 module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n");
+MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets");
 
 static int myri10ge_msi = 1;	/* enable msi by default */
 module_param(myri10ge_msi, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n");
+MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts");
 
 static int myri10ge_intr_coal_delay = 75;
 module_param(myri10ge_intr_coal_delay, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay\n");
+MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay");
 
 static int myri10ge_flow_control = 1;
 module_param(myri10ge_flow_control, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter\n");
+MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter");
 
 static int myri10ge_deassert_wait = 1;
 module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(myri10ge_deassert_wait,
-		 "Wait when deasserting legacy interrupts\n");
+		 "Wait when deasserting legacy interrupts");
 
 static int myri10ge_force_firmware = 0;
 module_param(myri10ge_force_firmware, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_force_firmware,
-		 "Force firmware to assume aligned completions\n");
+		 "Force firmware to assume aligned completions");
 
 static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
 module_param(myri10ge_initial_mtu, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
+MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU");
 
 static int myri10ge_napi_weight = 64;
 module_param(myri10ge_napi_weight, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight\n");
+MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight");
 
 static int myri10ge_watchdog_timeout = 1;
 module_param(myri10ge_watchdog_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout\n");
+MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout");
 
 static int myri10ge_max_irq_loops = 1048576;
 module_param(myri10ge_max_irq_loops, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_max_irq_loops,
-		 "Set stuck legacy IRQ detection threshold\n");
+		 "Set stuck legacy IRQ detection threshold");
 
 #define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK
 
@@ -289,21 +304,22 @@
 
 static int myri10ge_lro = 1;
 module_param(myri10ge_lro, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");
+MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload");
 
 static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
 module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");
+MODULE_PARM_DESC(myri10ge_lro_max_pkts,
+		 "Number of LRO packets to be aggregated");
 
 static int myri10ge_fill_thresh = 256;
 module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
+MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed");
 
 static int myri10ge_reset_recover = 1;
 
 static int myri10ge_wcfifo = 0;
 module_param(myri10ge_wcfifo, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
+MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled");
 
 #define MYRI10GE_FW_OFFSET 1024*1024
 #define MYRI10GE_HIGHPART_TO_U32(X) \
@@ -359,8 +375,10 @@
 		for (sleep_total = 0;
 		     sleep_total < 1000
 		     && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT);
-		     sleep_total += 10)
+		     sleep_total += 10) {
 			udelay(10);
+			mb();
+		}
 	} else {
 		/* use msleep for most command */
 		for (sleep_total = 0;
@@ -420,6 +438,10 @@
 				ptr += 1;
 			}
 		}
+		if (memcmp(ptr, "PC=", 3) == 0) {
+			ptr += 3;
+			mgp->product_code_string = ptr;
+		}
 		if (memcmp((const void *)ptr, "SN=", 3) == 0) {
 			ptr += 3;
 			mgp->serial_number = simple_strtoul(ptr, &ptr, 10);
@@ -442,7 +464,7 @@
 static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
 {
 	char __iomem *submit;
-	__be32 buf[16];
+	__be32 buf[16] __attribute__ ((__aligned__(8)));
 	u32 dma_low, dma_high;
 	int i;
 
@@ -609,13 +631,38 @@
 	return status;
 }
 
+int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
+{
+	struct myri10ge_cmd cmd;
+	int status;
+
+	/* probe for IPv6 TSO support */
+	mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+				   &cmd, 0);
+	if (status == 0) {
+		mgp->max_tso6 = cmd.data0;
+		mgp->features |= NETIF_F_TSO6;
+	}
+
+	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+	if (status != 0) {
+		dev_err(&mgp->pdev->dev,
+			"failed MXGEFW_CMD_GET_RX_RING_SIZE\n");
+		return -ENXIO;
+	}
+
+	mgp->max_intr_slots = 2 * (cmd.data0 / sizeof(struct mcp_dma_addr));
+
+	return 0;
+}
+
 static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
 {
 	char __iomem *submit;
-	__be32 buf[16];
+	__be32 buf[16] __attribute__ ((__aligned__(8)));
 	u32 dma_low, dma_high, size;
 	int status, i;
-	struct myri10ge_cmd cmd;
 
 	size = 0;
 	status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -635,7 +682,7 @@
 		}
 		dev_info(&mgp->pdev->dev,
 			 "Successfully adopted running firmware\n");
-		if (mgp->tx.boundary == 4096) {
+		if (mgp->tx_boundary == 4096) {
 			dev_warn(&mgp->pdev->dev,
 				 "Using firmware currently running on NIC"
 				 ".  For optimal\n");
@@ -646,7 +693,9 @@
 		}
 
 		mgp->fw_name = "adopted";
-		mgp->tx.boundary = 2048;
+		mgp->tx_boundary = 2048;
+		myri10ge_dummy_rdma(mgp, 1);
+		status = myri10ge_get_firmware_capabilities(mgp);
 		return status;
 	}
 
@@ -681,26 +730,18 @@
 	msleep(1);
 	mb();
 	i = 0;
-	while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20) {
-		msleep(1);
+	while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 9) {
+		msleep(1 << i);
 		i++;
 	}
 	if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {
 		dev_err(&mgp->pdev->dev, "handoff failed\n");
 		return -ENXIO;
 	}
-	dev_info(&mgp->pdev->dev, "handoff confirmed\n");
 	myri10ge_dummy_rdma(mgp, 1);
+	status = myri10ge_get_firmware_capabilities(mgp);
 
-	/* probe for IPv6 TSO support */
-	mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
-	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
-				   &cmd, 0);
-	if (status == 0) {
-		mgp->max_tso6 = cmd.data0;
-		mgp->features |= NETIF_F_TSO6;
-	}
-	return 0;
+	return status;
 }
 
 static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr)
@@ -772,7 +813,7 @@
 	 * transfers took to complete.
 	 */
 
-	len = mgp->tx.boundary;
+	len = mgp->tx_boundary;
 
 	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
 	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
@@ -834,17 +875,17 @@
 
 	/* Now exchange information about interrupts  */
 
-	bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
-	memset(mgp->rx_done.entry, 0, bytes);
+	bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
+	memset(mgp->ss.rx_done.entry, 0, bytes);
 	cmd.data0 = (u32) bytes;
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
-	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
-	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus);
+	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus);
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);
 
 	status |=
 	    myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
-	mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
+	mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
 				    &cmd, 0);
 	mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
@@ -858,17 +899,17 @@
 	}
 	put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
 
-	memset(mgp->rx_done.entry, 0, bytes);
+	memset(mgp->ss.rx_done.entry, 0, bytes);
 
 	/* reset mcp/driver shared state back to 0 */
-	mgp->tx.req = 0;
-	mgp->tx.done = 0;
-	mgp->tx.pkt_start = 0;
-	mgp->tx.pkt_done = 0;
-	mgp->rx_big.cnt = 0;
-	mgp->rx_small.cnt = 0;
-	mgp->rx_done.idx = 0;
-	mgp->rx_done.cnt = 0;
+	mgp->ss.tx.req = 0;
+	mgp->ss.tx.done = 0;
+	mgp->ss.tx.pkt_start = 0;
+	mgp->ss.tx.pkt_done = 0;
+	mgp->ss.rx_big.cnt = 0;
+	mgp->ss.rx_small.cnt = 0;
+	mgp->ss.rx_done.idx = 0;
+	mgp->ss.rx_done.cnt = 0;
 	mgp->link_changes = 0;
 	status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
 	myri10ge_change_pause(mgp, mgp->pause);
@@ -1020,9 +1061,10 @@
 				 * page into an skb */
 
 static inline int
-myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
 		 int bytes, int len, __wsum csum)
 {
+	struct myri10ge_priv *mgp = ss->mgp;
 	struct sk_buff *skb;
 	struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
 	int i, idx, hlen, remainder;
@@ -1052,11 +1094,10 @@
 		rx_frags[0].page_offset += MXGEFW_PAD;
 		rx_frags[0].size -= MXGEFW_PAD;
 		len -= MXGEFW_PAD;
-		lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
+		lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags,
 				  len, len,
-				 /* opaque, will come back in get_frag_header */
-				  (void *)(__force unsigned long)csum,
-				  csum);
+				  /* opaque, will come back in get_frag_header */
+				  (void *)(__force unsigned long)csum, csum);
 		return 1;
 	}
 
@@ -1096,10 +1137,11 @@
 	return 1;
 }
 
-static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
+static inline void
+myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
 {
-	struct pci_dev *pdev = mgp->pdev;
-	struct myri10ge_tx_buf *tx = &mgp->tx;
+	struct pci_dev *pdev = ss->mgp->pdev;
+	struct myri10ge_tx_buf *tx = &ss->tx;
 	struct sk_buff *skb;
 	int idx, len;
 
@@ -1117,8 +1159,8 @@
 		len = pci_unmap_len(&tx->info[idx], len);
 		pci_unmap_len_set(&tx->info[idx], len, 0);
 		if (skb) {
-			mgp->stats.tx_bytes += skb->len;
-			mgp->stats.tx_packets++;
+			ss->stats.tx_bytes += skb->len;
+			ss->stats.tx_packets++;
 			dev_kfree_skb_irq(skb);
 			if (len)
 				pci_unmap_single(pdev,
@@ -1134,16 +1176,18 @@
 		}
 	}
 	/* start the queue if we've stopped it */
-	if (netif_queue_stopped(mgp->dev)
+	if (netif_queue_stopped(ss->dev)
 	    && tx->req - tx->done < (tx->mask >> 1)) {
-		mgp->wake_queue++;
-		netif_wake_queue(mgp->dev);
+		tx->wake_queue++;
+		netif_wake_queue(ss->dev);
 	}
 }
 
-static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
+static inline int
+myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
 {
-	struct myri10ge_rx_done *rx_done = &mgp->rx_done;
+	struct myri10ge_rx_done *rx_done = &ss->rx_done;
+	struct myri10ge_priv *mgp = ss->mgp;
 	unsigned long rx_bytes = 0;
 	unsigned long rx_packets = 0;
 	unsigned long rx_ok;
@@ -1159,40 +1203,40 @@
 		rx_done->entry[idx].length = 0;
 		checksum = csum_unfold(rx_done->entry[idx].checksum);
 		if (length <= mgp->small_bytes)
-			rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small,
+			rx_ok = myri10ge_rx_done(ss, &ss->rx_small,
 						 mgp->small_bytes,
 						 length, checksum);
 		else
-			rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
+			rx_ok = myri10ge_rx_done(ss, &ss->rx_big,
 						 mgp->big_bytes,
 						 length, checksum);
 		rx_packets += rx_ok;
 		rx_bytes += rx_ok * (unsigned long)length;
 		cnt++;
-		idx = cnt & (myri10ge_max_intr_slots - 1);
+		idx = cnt & (mgp->max_intr_slots - 1);
 		work_done++;
 	}
 	rx_done->idx = idx;
 	rx_done->cnt = cnt;
-	mgp->stats.rx_packets += rx_packets;
-	mgp->stats.rx_bytes += rx_bytes;
+	ss->stats.rx_packets += rx_packets;
+	ss->stats.rx_bytes += rx_bytes;
 
 	if (myri10ge_lro)
 		lro_flush_all(&rx_done->lro_mgr);
 
 	/* restock receive rings if needed */
-	if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
-		myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+	if (ss->rx_small.fill_cnt - ss->rx_small.cnt < myri10ge_fill_thresh)
+		myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
 					mgp->small_bytes + MXGEFW_PAD, 0);
-	if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
-		myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+	if (ss->rx_big.fill_cnt - ss->rx_big.cnt < myri10ge_fill_thresh)
+		myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
 
 	return work_done;
 }
 
 static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
 {
-	struct mcp_irq_data *stats = mgp->fw_stats;
+	struct mcp_irq_data *stats = mgp->ss.fw_stats;
 
 	if (unlikely(stats->stats_updated)) {
 		unsigned link_up = ntohl(stats->link_up);
@@ -1219,9 +1263,9 @@
 			}
 		}
 		if (mgp->rdma_tags_available !=
-		    ntohl(mgp->fw_stats->rdma_tags_available)) {
+		    ntohl(stats->rdma_tags_available)) {
 			mgp->rdma_tags_available =
-			    ntohl(mgp->fw_stats->rdma_tags_available);
+			    ntohl(stats->rdma_tags_available);
 			printk(KERN_WARNING "myri10ge: %s: RDMA timed out! "
 			       "%d tags left\n", mgp->dev->name,
 			       mgp->rdma_tags_available);
@@ -1234,26 +1278,27 @@
 
 static int myri10ge_poll(struct napi_struct *napi, int budget)
 {
-	struct myri10ge_priv *mgp =
-	    container_of(napi, struct myri10ge_priv, napi);
-	struct net_device *netdev = mgp->dev;
+	struct myri10ge_slice_state *ss =
+	    container_of(napi, struct myri10ge_slice_state, napi);
+	struct net_device *netdev = ss->mgp->dev;
 	int work_done;
 
 	/* process as many rx events as NAPI will allow */
-	work_done = myri10ge_clean_rx_done(mgp, budget);
+	work_done = myri10ge_clean_rx_done(ss, budget);
 
 	if (work_done < budget) {
 		netif_rx_complete(netdev, napi);
-		put_be32(htonl(3), mgp->irq_claim);
+		put_be32(htonl(3), ss->irq_claim);
 	}
 	return work_done;
 }
 
 static irqreturn_t myri10ge_intr(int irq, void *arg)
 {
-	struct myri10ge_priv *mgp = arg;
-	struct mcp_irq_data *stats = mgp->fw_stats;
-	struct myri10ge_tx_buf *tx = &mgp->tx;
+	struct myri10ge_slice_state *ss = arg;
+	struct myri10ge_priv *mgp = ss->mgp;
+	struct mcp_irq_data *stats = ss->fw_stats;
+	struct myri10ge_tx_buf *tx = &ss->tx;
 	u32 send_done_count;
 	int i;
 
@@ -1264,7 +1309,7 @@
 	/* low bit indicates receives are present, so schedule
 	 * napi poll handler */
 	if (stats->valid & 1)
-		netif_rx_schedule(mgp->dev, &mgp->napi);
+		netif_rx_schedule(ss->dev, &ss->napi);
 
 	if (!mgp->msi_enabled) {
 		put_be32(0, mgp->irq_deassert);
@@ -1281,7 +1326,7 @@
 		/* check for transmit completes and receives */
 		send_done_count = ntohl(stats->send_done_count);
 		if (send_done_count != tx->pkt_done)
-			myri10ge_tx_done(mgp, (int)send_done_count);
+			myri10ge_tx_done(ss, (int)send_done_count);
 		if (unlikely(i > myri10ge_max_irq_loops)) {
 			printk(KERN_WARNING "myri10ge: %s: irq stuck?\n",
 			       mgp->dev->name);
@@ -1296,16 +1341,46 @@
 
 	myri10ge_check_statblock(mgp);
 
-	put_be32(htonl(3), mgp->irq_claim + 1);
+	put_be32(htonl(3), ss->irq_claim + 1);
 	return (IRQ_HANDLED);
 }
 
 static int
 myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
+	struct myri10ge_priv *mgp = netdev_priv(netdev);
+	char *ptr;
+	int i;
+
 	cmd->autoneg = AUTONEG_DISABLE;
 	cmd->speed = SPEED_10000;
 	cmd->duplex = DUPLEX_FULL;
+
+	/*
+	 * parse the product code to deterimine the interface type
+	 * (CX4, XFP, Quad Ribbon Fiber) by looking at the character
+	 * after the 3rd dash in the driver's cached copy of the
+	 * EEPROM's product code string.
+	 */
+	ptr = mgp->product_code_string;
+	if (ptr == NULL) {
+		printk(KERN_ERR "myri10ge: %s: Missing product code\n",
+		       netdev->name);
+		return 0;
+	}
+	for (i = 0; i < 3; i++, ptr++) {
+		ptr = strchr(ptr, '-');
+		if (ptr == NULL) {
+			printk(KERN_ERR "myri10ge: %s: Invalid product "
+			       "code %s\n", netdev->name,
+			       mgp->product_code_string);
+			return 0;
+		}
+	}
+	if (*ptr == 'R' || *ptr == 'Q') {
+		/* We've found either an XFP or quad ribbon fiber */
+		cmd->port = PORT_FIBRE;
+	}
 	return 0;
 }
 
@@ -1324,6 +1399,7 @@
 myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
 {
 	struct myri10ge_priv *mgp = netdev_priv(netdev);
+
 	coal->rx_coalesce_usecs = mgp->intr_coal_delay;
 	return 0;
 }
@@ -1370,10 +1446,10 @@
 {
 	struct myri10ge_priv *mgp = netdev_priv(netdev);
 
-	ring->rx_mini_max_pending = mgp->rx_small.mask + 1;
-	ring->rx_max_pending = mgp->rx_big.mask + 1;
+	ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1;
+	ring->rx_max_pending = mgp->ss.rx_big.mask + 1;
 	ring->rx_jumbo_max_pending = 0;
-	ring->tx_max_pending = mgp->rx_small.mask + 1;
+	ring->tx_max_pending = mgp->ss.rx_small.mask + 1;
 	ring->rx_mini_pending = ring->rx_mini_max_pending;
 	ring->rx_pending = ring->rx_max_pending;
 	ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
@@ -1383,6 +1459,7 @@
 static u32 myri10ge_get_rx_csum(struct net_device *netdev)
 {
 	struct myri10ge_priv *mgp = netdev_priv(netdev);
+
 	if (mgp->csum_flag)
 		return 1;
 	else
@@ -1392,6 +1469,7 @@
 static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
 {
 	struct myri10ge_priv *mgp = netdev_priv(netdev);
+
 	if (csum_enabled)
 		mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
 	else
@@ -1411,7 +1489,7 @@
 	return 0;
 }
 
-static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
+static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
 	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
 	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
 	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
@@ -1421,28 +1499,39 @@
 	/* device-specific stats */
 	"tx_boundary", "WC", "irq", "MSI",
 	"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
-	"serial_number", "tx_pkt_start", "tx_pkt_done",
-	"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
-	"wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
+	"serial_number", "watchdog_resets",
 	"link_changes", "link_up", "dropped_link_overflow",
 	"dropped_link_error_or_filtered",
 	"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
 	"dropped_unicast_filtered", "dropped_multicast_filtered",
 	"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
-	"dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
+	"dropped_no_big_buffer"
+};
+
+static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = {
+	"----------- slice ---------",
+	"tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done",
+	"rx_small_cnt", "rx_big_cnt",
+	"wake_queue", "stop_queue", "tx_linearized", "LRO aggregated",
+	    "LRO flushed",
 	"LRO avg aggr", "LRO no_desc"
 };
 
 #define MYRI10GE_NET_STATS_LEN      21
-#define MYRI10GE_STATS_LEN	ARRAY_SIZE(myri10ge_gstrings_stats)
+#define MYRI10GE_MAIN_STATS_LEN  ARRAY_SIZE(myri10ge_gstrings_main_stats)
+#define MYRI10GE_SLICE_STATS_LEN  ARRAY_SIZE(myri10ge_gstrings_slice_stats)
 
 static void
 myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
 {
 	switch (stringset) {
 	case ETH_SS_STATS:
-		memcpy(data, *myri10ge_gstrings_stats,
-		       sizeof(myri10ge_gstrings_stats));
+		memcpy(data, *myri10ge_gstrings_main_stats,
+		       sizeof(myri10ge_gstrings_main_stats));
+		data += sizeof(myri10ge_gstrings_main_stats);
+		memcpy(data, *myri10ge_gstrings_slice_stats,
+		       sizeof(myri10ge_gstrings_slice_stats));
+		data += sizeof(myri10ge_gstrings_slice_stats);
 		break;
 	}
 }
@@ -1451,7 +1540,7 @@
 {
 	switch (sset) {
 	case ETH_SS_STATS:
-		return MYRI10GE_STATS_LEN;
+		return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -1462,12 +1551,13 @@
 			   struct ethtool_stats *stats, u64 * data)
 {
 	struct myri10ge_priv *mgp = netdev_priv(netdev);
+	struct myri10ge_slice_state *ss;
 	int i;
 
 	for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
 		data[i] = ((unsigned long *)&mgp->stats)[i];
 
-	data[i++] = (unsigned int)mgp->tx.boundary;
+	data[i++] = (unsigned int)mgp->tx_boundary;
 	data[i++] = (unsigned int)mgp->wc_enabled;
 	data[i++] = (unsigned int)mgp->pdev->irq;
 	data[i++] = (unsigned int)mgp->msi_enabled;
@@ -1475,40 +1565,44 @@
 	data[i++] = (unsigned int)mgp->write_dma;
 	data[i++] = (unsigned int)mgp->read_write_dma;
 	data[i++] = (unsigned int)mgp->serial_number;
-	data[i++] = (unsigned int)mgp->tx.pkt_start;
-	data[i++] = (unsigned int)mgp->tx.pkt_done;
-	data[i++] = (unsigned int)mgp->tx.req;
-	data[i++] = (unsigned int)mgp->tx.done;
-	data[i++] = (unsigned int)mgp->rx_small.cnt;
-	data[i++] = (unsigned int)mgp->rx_big.cnt;
-	data[i++] = (unsigned int)mgp->wake_queue;
-	data[i++] = (unsigned int)mgp->stop_queue;
 	data[i++] = (unsigned int)mgp->watchdog_resets;
-	data[i++] = (unsigned int)mgp->tx_linearized;
 	data[i++] = (unsigned int)mgp->link_changes;
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
+
+	/* firmware stats are useful only in the first slice */
+	ss = &mgp->ss;
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
 	data[i++] =
-	    (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_pause);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_phy);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_crc32);
+	    (unsigned int)ntohl(ss->fw_stats->dropped_link_error_or_filtered);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_pause);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_phy);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_crc32);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_unicast_filtered);
 	data[i++] =
-	    (unsigned int)ntohl(mgp->fw_stats->dropped_unicast_filtered);
-	data[i++] =
-	    (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
-	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
-	data[i++] = mgp->rx_done.lro_mgr.stats.aggregated;
-	data[i++] = mgp->rx_done.lro_mgr.stats.flushed;
-	if (mgp->rx_done.lro_mgr.stats.flushed)
-		data[i++] = mgp->rx_done.lro_mgr.stats.aggregated /
-		    mgp->rx_done.lro_mgr.stats.flushed;
+	    (unsigned int)ntohl(ss->fw_stats->dropped_multicast_filtered);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_runt);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_overrun);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
+	data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
+
+	data[i++] = 0;
+	data[i++] = (unsigned int)ss->tx.pkt_start;
+	data[i++] = (unsigned int)ss->tx.pkt_done;
+	data[i++] = (unsigned int)ss->tx.req;
+	data[i++] = (unsigned int)ss->tx.done;
+	data[i++] = (unsigned int)ss->rx_small.cnt;
+	data[i++] = (unsigned int)ss->rx_big.cnt;
+	data[i++] = (unsigned int)ss->tx.wake_queue;
+	data[i++] = (unsigned int)ss->tx.stop_queue;
+	data[i++] = (unsigned int)ss->tx.linearized;
+	data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
+	data[i++] = ss->rx_done.lro_mgr.stats.flushed;
+	if (ss->rx_done.lro_mgr.stats.flushed)
+		data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
+		    ss->rx_done.lro_mgr.stats.flushed;
 	else
 		data[i++] = 0;
-	data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
+	data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
 }
 
 static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1544,19 +1638,17 @@
 	.get_msglevel = myri10ge_get_msglevel
 };
 
-static int myri10ge_allocate_rings(struct net_device *dev)
+static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
 {
-	struct myri10ge_priv *mgp;
+	struct myri10ge_priv *mgp = ss->mgp;
 	struct myri10ge_cmd cmd;
+	struct net_device *dev = mgp->dev;
 	int tx_ring_size, rx_ring_size;
 	int tx_ring_entries, rx_ring_entries;
 	int i, status;
 	size_t bytes;
 
-	mgp = netdev_priv(dev);
-
 	/* get ring sizes */
-
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
 	tx_ring_size = cmd.data0;
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
@@ -1566,144 +1658,142 @@
 
 	tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send);
 	rx_ring_entries = rx_ring_size / sizeof(struct mcp_dma_addr);
-	mgp->tx.mask = tx_ring_entries - 1;
-	mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1;
+	ss->tx.mask = tx_ring_entries - 1;
+	ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1;
 
 	status = -ENOMEM;
 
 	/* allocate the host shadow rings */
 
 	bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4)
-	    * sizeof(*mgp->tx.req_list);
-	mgp->tx.req_bytes = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->tx.req_bytes == NULL)
+	    * sizeof(*ss->tx.req_list);
+	ss->tx.req_bytes = kzalloc(bytes, GFP_KERNEL);
+	if (ss->tx.req_bytes == NULL)
 		goto abort_with_nothing;
 
 	/* ensure req_list entries are aligned to 8 bytes */
-	mgp->tx.req_list = (struct mcp_kreq_ether_send *)
-	    ALIGN((unsigned long)mgp->tx.req_bytes, 8);
+	ss->tx.req_list = (struct mcp_kreq_ether_send *)
+	    ALIGN((unsigned long)ss->tx.req_bytes, 8);
 
-	bytes = rx_ring_entries * sizeof(*mgp->rx_small.shadow);
-	mgp->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->rx_small.shadow == NULL)
+	bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow);
+	ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
+	if (ss->rx_small.shadow == NULL)
 		goto abort_with_tx_req_bytes;
 
-	bytes = rx_ring_entries * sizeof(*mgp->rx_big.shadow);
-	mgp->rx_big.shadow = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->rx_big.shadow == NULL)
+	bytes = rx_ring_entries * sizeof(*ss->rx_big.shadow);
+	ss->rx_big.shadow = kzalloc(bytes, GFP_KERNEL);
+	if (ss->rx_big.shadow == NULL)
 		goto abort_with_rx_small_shadow;
 
 	/* allocate the host info rings */
 
-	bytes = tx_ring_entries * sizeof(*mgp->tx.info);
-	mgp->tx.info = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->tx.info == NULL)
+	bytes = tx_ring_entries * sizeof(*ss->tx.info);
+	ss->tx.info = kzalloc(bytes, GFP_KERNEL);
+	if (ss->tx.info == NULL)
 		goto abort_with_rx_big_shadow;
 
-	bytes = rx_ring_entries * sizeof(*mgp->rx_small.info);
-	mgp->rx_small.info = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->rx_small.info == NULL)
+	bytes = rx_ring_entries * sizeof(*ss->rx_small.info);
+	ss->rx_small.info = kzalloc(bytes, GFP_KERNEL);
+	if (ss->rx_small.info == NULL)
 		goto abort_with_tx_info;
 
-	bytes = rx_ring_entries * sizeof(*mgp->rx_big.info);
-	mgp->rx_big.info = kzalloc(bytes, GFP_KERNEL);
-	if (mgp->rx_big.info == NULL)
+	bytes = rx_ring_entries * sizeof(*ss->rx_big.info);
+	ss->rx_big.info = kzalloc(bytes, GFP_KERNEL);
+	if (ss->rx_big.info == NULL)
 		goto abort_with_rx_small_info;
 
 	/* Fill the receive rings */
-	mgp->rx_big.cnt = 0;
-	mgp->rx_small.cnt = 0;
-	mgp->rx_big.fill_cnt = 0;
-	mgp->rx_small.fill_cnt = 0;
-	mgp->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
-	mgp->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
-	mgp->rx_small.watchdog_needed = 0;
-	mgp->rx_big.watchdog_needed = 0;
-	myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+	ss->rx_big.cnt = 0;
+	ss->rx_small.cnt = 0;
+	ss->rx_big.fill_cnt = 0;
+	ss->rx_small.fill_cnt = 0;
+	ss->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
+	ss->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
+	ss->rx_small.watchdog_needed = 0;
+	ss->rx_big.watchdog_needed = 0;
+	myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
 				mgp->small_bytes + MXGEFW_PAD, 0);
 
-	if (mgp->rx_small.fill_cnt < mgp->rx_small.mask + 1) {
+	if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) {
 		printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
-		       dev->name, mgp->rx_small.fill_cnt);
+		       dev->name, ss->rx_small.fill_cnt);
 		goto abort_with_rx_small_ring;
 	}
 
-	myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
-	if (mgp->rx_big.fill_cnt < mgp->rx_big.mask + 1) {
+	myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
+	if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) {
 		printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
-		       dev->name, mgp->rx_big.fill_cnt);
+		       dev->name, ss->rx_big.fill_cnt);
 		goto abort_with_rx_big_ring;
 	}
 
 	return 0;
 
 abort_with_rx_big_ring:
-	for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
-		int idx = i & mgp->rx_big.mask;
-		myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+	for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
+		int idx = i & ss->rx_big.mask;
+		myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx],
 				       mgp->big_bytes);
-		put_page(mgp->rx_big.info[idx].page);
+		put_page(ss->rx_big.info[idx].page);
 	}
 
 abort_with_rx_small_ring:
-	for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
-		int idx = i & mgp->rx_small.mask;
-		myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+	for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) {
+		int idx = i & ss->rx_small.mask;
+		myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx],
 				       mgp->small_bytes + MXGEFW_PAD);
-		put_page(mgp->rx_small.info[idx].page);
+		put_page(ss->rx_small.info[idx].page);
 	}
 
-	kfree(mgp->rx_big.info);
+	kfree(ss->rx_big.info);
 
 abort_with_rx_small_info:
-	kfree(mgp->rx_small.info);
+	kfree(ss->rx_small.info);
 
 abort_with_tx_info:
-	kfree(mgp->tx.info);
+	kfree(ss->tx.info);
 
 abort_with_rx_big_shadow:
-	kfree(mgp->rx_big.shadow);
+	kfree(ss->rx_big.shadow);
 
 abort_with_rx_small_shadow:
-	kfree(mgp->rx_small.shadow);
+	kfree(ss->rx_small.shadow);
 
 abort_with_tx_req_bytes:
-	kfree(mgp->tx.req_bytes);
-	mgp->tx.req_bytes = NULL;
-	mgp->tx.req_list = NULL;
+	kfree(ss->tx.req_bytes);
+	ss->tx.req_bytes = NULL;
+	ss->tx.req_list = NULL;
 
 abort_with_nothing:
 	return status;
 }
 
-static void myri10ge_free_rings(struct net_device *dev)
+static void myri10ge_free_rings(struct myri10ge_slice_state *ss)
 {
-	struct myri10ge_priv *mgp;
+	struct myri10ge_priv *mgp = ss->mgp;
 	struct sk_buff *skb;
 	struct myri10ge_tx_buf *tx;
 	int i, len, idx;
 
-	mgp = netdev_priv(dev);
-
-	for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
-		idx = i & mgp->rx_big.mask;
-		if (i == mgp->rx_big.fill_cnt - 1)
-			mgp->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
-		myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+	for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
+		idx = i & ss->rx_big.mask;
+		if (i == ss->rx_big.fill_cnt - 1)
+			ss->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
+		myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx],
 				       mgp->big_bytes);
-		put_page(mgp->rx_big.info[idx].page);
+		put_page(ss->rx_big.info[idx].page);
 	}
 
-	for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
-		idx = i & mgp->rx_small.mask;
-		if (i == mgp->rx_small.fill_cnt - 1)
-			mgp->rx_small.info[idx].page_offset =
+	for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) {
+		idx = i & ss->rx_small.mask;
+		if (i == ss->rx_small.fill_cnt - 1)
+			ss->rx_small.info[idx].page_offset =
 			    MYRI10GE_ALLOC_SIZE;
-		myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+		myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx],
 				       mgp->small_bytes + MXGEFW_PAD);
-		put_page(mgp->rx_small.info[idx].page);
+		put_page(ss->rx_small.info[idx].page);
 	}
-	tx = &mgp->tx;
+	tx = &ss->tx;
 	while (tx->done != tx->req) {
 		idx = tx->done & tx->mask;
 		skb = tx->info[idx].skb;
@@ -1714,7 +1804,7 @@
 		len = pci_unmap_len(&tx->info[idx], len);
 		pci_unmap_len_set(&tx->info[idx], len, 0);
 		if (skb) {
-			mgp->stats.tx_dropped++;
+			ss->stats.tx_dropped++;
 			dev_kfree_skb_any(skb);
 			if (len)
 				pci_unmap_single(mgp->pdev,
@@ -1729,19 +1819,19 @@
 					       PCI_DMA_TODEVICE);
 		}
 	}
-	kfree(mgp->rx_big.info);
+	kfree(ss->rx_big.info);
 
-	kfree(mgp->rx_small.info);
+	kfree(ss->rx_small.info);
 
-	kfree(mgp->tx.info);
+	kfree(ss->tx.info);
 
-	kfree(mgp->rx_big.shadow);
+	kfree(ss->rx_big.shadow);
 
-	kfree(mgp->rx_small.shadow);
+	kfree(ss->rx_small.shadow);
 
-	kfree(mgp->tx.req_bytes);
-	mgp->tx.req_bytes = NULL;
-	mgp->tx.req_list = NULL;
+	kfree(ss->tx.req_bytes);
+	ss->tx.req_bytes = NULL;
+	ss->tx.req_list = NULL;
 }
 
 static int myri10ge_request_irq(struct myri10ge_priv *mgp)
@@ -1840,13 +1930,11 @@
 
 static int myri10ge_open(struct net_device *dev)
 {
-	struct myri10ge_priv *mgp;
+	struct myri10ge_priv *mgp = netdev_priv(dev);
 	struct myri10ge_cmd cmd;
 	struct net_lro_mgr *lro_mgr;
 	int status, big_pow2;
 
-	mgp = netdev_priv(dev);
-
 	if (mgp->running != MYRI10GE_ETH_STOPPED)
 		return -EBUSY;
 
@@ -1883,16 +1971,16 @@
 	/* get the lanai pointers to the send and receive rings */
 
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
-	mgp->tx.lanai =
+	mgp->ss.tx.lanai =
 	    (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0);
 
 	status |=
 	    myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0);
-	mgp->rx_small.lanai =
+	mgp->ss.rx_small.lanai =
 	    (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
 
 	status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
-	mgp->rx_big.lanai =
+	mgp->ss.rx_big.lanai =
 	    (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
 
 	if (status != 0) {
@@ -1904,15 +1992,15 @@
 	}
 
 	if (myri10ge_wcfifo && mgp->wc_enabled) {
-		mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
-		mgp->rx_small.wc_fifo =
+		mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
+		mgp->ss.rx_small.wc_fifo =
 		    (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
-		mgp->rx_big.wc_fifo =
+		mgp->ss.rx_big.wc_fifo =
 		    (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
 	} else {
-		mgp->tx.wc_fifo = NULL;
-		mgp->rx_small.wc_fifo = NULL;
-		mgp->rx_big.wc_fifo = NULL;
+		mgp->ss.tx.wc_fifo = NULL;
+		mgp->ss.rx_small.wc_fifo = NULL;
+		mgp->ss.rx_big.wc_fifo = NULL;
 	}
 
 	/* Firmware needs the big buff size as a power of 2.  Lie and
@@ -1929,7 +2017,7 @@
 		mgp->big_bytes = big_pow2;
 	}
 
-	status = myri10ge_allocate_rings(dev);
+	status = myri10ge_allocate_rings(&mgp->ss);
 	if (status != 0)
 		goto abort_with_irq;
 
@@ -1948,12 +2036,12 @@
 		goto abort_with_rings;
 	}
 
-	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
-	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
+	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus);
+	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus);
 	cmd.data2 = sizeof(struct mcp_irq_data);
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
 	if (status == -ENOSYS) {
-		dma_addr_t bus = mgp->fw_stats_bus;
+		dma_addr_t bus = mgp->ss.fw_stats_bus;
 		bus += offsetof(struct mcp_irq_data, send_done_count);
 		cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
 		cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
@@ -1974,20 +2062,20 @@
 	mgp->link_state = ~0U;
 	mgp->rdma_tags_available = 15;
 
-	lro_mgr = &mgp->rx_done.lro_mgr;
+	lro_mgr = &mgp->ss.rx_done.lro_mgr;
 	lro_mgr->dev = dev;
 	lro_mgr->features = LRO_F_NAPI;
 	lro_mgr->ip_summed = CHECKSUM_COMPLETE;
 	lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
 	lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
-	lro_mgr->lro_arr = mgp->rx_done.lro_desc;
+	lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc;
 	lro_mgr->get_frag_header = myri10ge_get_frag_header;
 	lro_mgr->max_aggr = myri10ge_lro_max_pkts;
 	lro_mgr->frag_align_pad = 2;
 	if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
 		lro_mgr->max_aggr = MAX_SKB_FRAGS;
 
-	napi_enable(&mgp->napi);	/* must happen prior to any irq */
+	napi_enable(&mgp->ss.napi);	/* must happen prior to any irq */
 
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
 	if (status) {
@@ -1996,8 +2084,8 @@
 		goto abort_with_rings;
 	}
 
-	mgp->wake_queue = 0;
-	mgp->stop_queue = 0;
+	mgp->ss.tx.wake_queue = 0;
+	mgp->ss.tx.stop_queue = 0;
 	mgp->running = MYRI10GE_ETH_RUNNING;
 	mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
 	add_timer(&mgp->watchdog_timer);
@@ -2005,7 +2093,7 @@
 	return 0;
 
 abort_with_rings:
-	myri10ge_free_rings(dev);
+	myri10ge_free_rings(&mgp->ss);
 
 abort_with_irq:
 	myri10ge_free_irq(mgp);
@@ -2017,21 +2105,19 @@
 
 static int myri10ge_close(struct net_device *dev)
 {
-	struct myri10ge_priv *mgp;
+	struct myri10ge_priv *mgp = netdev_priv(dev);
 	struct myri10ge_cmd cmd;
 	int status, old_down_cnt;
 
-	mgp = netdev_priv(dev);
-
 	if (mgp->running != MYRI10GE_ETH_RUNNING)
 		return 0;
 
-	if (mgp->tx.req_bytes == NULL)
+	if (mgp->ss.tx.req_bytes == NULL)
 		return 0;
 
 	del_timer_sync(&mgp->watchdog_timer);
 	mgp->running = MYRI10GE_ETH_STOPPING;
-	napi_disable(&mgp->napi);
+	napi_disable(&mgp->ss.napi);
 	netif_carrier_off(dev);
 	netif_stop_queue(dev);
 	old_down_cnt = mgp->down_cnt;
@@ -2047,7 +2133,7 @@
 
 	netif_tx_disable(dev);
 	myri10ge_free_irq(mgp);
-	myri10ge_free_rings(dev);
+	myri10ge_free_rings(&mgp->ss);
 
 	mgp->running = MYRI10GE_ETH_STOPPED;
 	return 0;
@@ -2143,7 +2229,7 @@
 
 /*
  * Transmit a packet.  We need to split the packet so that a single
- * segment does not cross myri10ge->tx.boundary, so this makes segment
+ * segment does not cross myri10ge->tx_boundary, so this makes segment
  * counting tricky.  So rather than try to count segments up front, we
  * just give up if there are too few segments to hold a reasonably
  * fragmented packet currently available.  If we run
@@ -2154,8 +2240,9 @@
 static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct myri10ge_priv *mgp = netdev_priv(dev);
+	struct myri10ge_slice_state *ss;
 	struct mcp_kreq_ether_send *req;
-	struct myri10ge_tx_buf *tx = &mgp->tx;
+	struct myri10ge_tx_buf *tx;
 	struct skb_frag_struct *frag;
 	dma_addr_t bus;
 	u32 low;
@@ -2166,6 +2253,9 @@
 	int cum_len, seglen, boundary, rdma_count;
 	u8 flags, odd_flag;
 
+	/* always transmit through slot 0 */
+	ss = &mgp->ss;
+	tx = &ss->tx;
 again:
 	req = tx->req_list;
 	avail = tx->mask - 1 - (tx->req - tx->done);
@@ -2180,7 +2270,7 @@
 
 	if ((unlikely(avail < max_segments))) {
 		/* we are out of transmit resources */
-		mgp->stop_queue++;
+		tx->stop_queue++;
 		netif_stop_queue(dev);
 		return 1;
 	}
@@ -2242,7 +2332,7 @@
 			if (skb_padto(skb, ETH_ZLEN)) {
 				/* The packet is gone, so we must
 				 * return 0 */
-				mgp->stats.tx_dropped += 1;
+				ss->stats.tx_dropped += 1;
 				return 0;
 			}
 			/* adjust the len to account for the zero pad
@@ -2284,7 +2374,7 @@
 
 	while (1) {
 		/* Break the SKB or Fragment up into pieces which
-		 * do not cross mgp->tx.boundary */
+		 * do not cross mgp->tx_boundary */
 		low = MYRI10GE_LOWPART_TO_U32(bus);
 		high_swapped = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
 		while (len) {
@@ -2294,7 +2384,8 @@
 			if (unlikely(count == max_segments))
 				goto abort_linearize;
 
-			boundary = (low + tx->boundary) & ~(tx->boundary - 1);
+			boundary =
+			    (low + mgp->tx_boundary) & ~(mgp->tx_boundary - 1);
 			seglen = boundary - low;
 			if (seglen > len)
 				seglen = len;
@@ -2378,7 +2469,7 @@
 		myri10ge_submit_req_wc(tx, tx->req_list, count);
 	tx->pkt_start++;
 	if ((avail - count) < MXGEFW_MAX_SEND_DESC) {
-		mgp->stop_queue++;
+		tx->stop_queue++;
 		netif_stop_queue(dev);
 	}
 	dev->trans_start = jiffies;
@@ -2420,12 +2511,12 @@
 	if (skb_linearize(skb))
 		goto drop;
 
-	mgp->tx_linearized++;
+	tx->linearized++;
 	goto again;
 
 drop:
 	dev_kfree_skb_any(skb);
-	mgp->stats.tx_dropped += 1;
+	ss->stats.tx_dropped += 1;
 	return 0;
 
 }
@@ -2433,7 +2524,7 @@
 static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sk_buff *segs, *curr;
-	struct myri10ge_priv *mgp = dev->priv;
+	struct myri10ge_priv *mgp = netdev_priv(dev);
 	int status;
 
 	segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
@@ -2473,14 +2564,13 @@
 
 static void myri10ge_set_multicast_list(struct net_device *dev)
 {
+	struct myri10ge_priv *mgp = netdev_priv(dev);
 	struct myri10ge_cmd cmd;
-	struct myri10ge_priv *mgp;
 	struct dev_mc_list *mc_list;
 	__be32 data[2] = { 0, 0 };
 	int err;
 	DECLARE_MAC_BUF(mac);
 
-	mgp = netdev_priv(dev);
 	/* can be called from atomic contexts,
 	 * pass 1 to force atomicity in myri10ge_send_cmd() */
 	myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
@@ -2616,13 +2706,14 @@
 	ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
 	if (ext_type != PCI_EXP_TYPE_ROOT_PORT) {
 		if (myri10ge_ecrc_enable > 1) {
-			struct pci_dev *old_bridge = bridge;
+			struct pci_dev *prev_bridge, *old_bridge = bridge;
 
 			/* Walk the hierarchy up to the root port
 			 * where ECRC has to be enabled */
 			do {
+				prev_bridge = bridge;
 				bridge = bridge->bus->self;
-				if (!bridge) {
+				if (!bridge || prev_bridge == bridge) {
 					dev_err(dev,
 						"Failed to find root port"
 						" to force ECRC\n");
@@ -2681,9 +2772,9 @@
  * already been enabled, then it must use a firmware image which works
  * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it
  * should also ensure that it never gives the device a Read-DMA which is
- * larger than 2KB by setting the tx.boundary to 2KB.  If ECRC is
+ * larger than 2KB by setting the tx_boundary to 2KB.  If ECRC is
  * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat)
- * firmware image, and set tx.boundary to 4KB.
+ * firmware image, and set tx_boundary to 4KB.
  */
 
 static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
@@ -2692,7 +2783,7 @@
 	struct device *dev = &pdev->dev;
 	int status;
 
-	mgp->tx.boundary = 4096;
+	mgp->tx_boundary = 4096;
 	/*
 	 * Verify the max read request size was set to 4KB
 	 * before trying the test with 4KB.
@@ -2704,7 +2795,7 @@
 	}
 	if (status != 4096) {
 		dev_warn(dev, "Max Read Request size != 4096 (%d)\n", status);
-		mgp->tx.boundary = 2048;
+		mgp->tx_boundary = 2048;
 	}
 	/*
 	 * load the optimized firmware (which assumes aligned PCIe
@@ -2737,7 +2828,7 @@
 			 "Please install up to date fw\n");
 abort:
 	/* fall back to using the unaligned firmware */
-	mgp->tx.boundary = 2048;
+	mgp->tx_boundary = 2048;
 	mgp->fw_name = myri10ge_fw_unaligned;
 
 }
@@ -2758,7 +2849,7 @@
 		if (link_width < 8) {
 			dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
 				 link_width);
-			mgp->tx.boundary = 4096;
+			mgp->tx_boundary = 4096;
 			mgp->fw_name = myri10ge_fw_aligned;
 		} else {
 			myri10ge_firmware_probe(mgp);
@@ -2767,12 +2858,12 @@
 		if (myri10ge_force_firmware == 1) {
 			dev_info(&mgp->pdev->dev,
 				 "Assuming aligned completions (forced)\n");
-			mgp->tx.boundary = 4096;
+			mgp->tx_boundary = 4096;
 			mgp->fw_name = myri10ge_fw_aligned;
 		} else {
 			dev_info(&mgp->pdev->dev,
 				 "Assuming unaligned completions (forced)\n");
-			mgp->tx.boundary = 2048;
+			mgp->tx_boundary = 2048;
 			mgp->fw_name = myri10ge_fw_unaligned;
 		}
 	}
@@ -2889,6 +2980,7 @@
 {
 	struct myri10ge_priv *mgp =
 	    container_of(work, struct myri10ge_priv, watchdog_work);
+	struct myri10ge_tx_buf *tx;
 	u32 reboot;
 	int status;
 	u16 cmd, vendor;
@@ -2938,15 +3030,16 @@
 
 		printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
 		       mgp->dev->name);
+		tx = &mgp->ss.tx;
 		printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
-		       mgp->dev->name, mgp->tx.req, mgp->tx.done,
-		       mgp->tx.pkt_start, mgp->tx.pkt_done,
-		       (int)ntohl(mgp->fw_stats->send_done_count));
+		       mgp->dev->name, tx->req, tx->done,
+		       tx->pkt_start, tx->pkt_done,
+		       (int)ntohl(mgp->ss.fw_stats->send_done_count));
 		msleep(2000);
 		printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
-		       mgp->dev->name, mgp->tx.req, mgp->tx.done,
-		       mgp->tx.pkt_start, mgp->tx.pkt_done,
-		       (int)ntohl(mgp->fw_stats->send_done_count));
+		       mgp->dev->name, tx->req, tx->done,
+		       tx->pkt_start, tx->pkt_done,
+		       (int)ntohl(mgp->ss.fw_stats->send_done_count));
 	}
 	rtnl_lock();
 	myri10ge_close(mgp->dev);
@@ -2969,28 +3062,31 @@
 static void myri10ge_watchdog_timer(unsigned long arg)
 {
 	struct myri10ge_priv *mgp;
+	struct myri10ge_slice_state *ss;
 	u32 rx_pause_cnt;
 
 	mgp = (struct myri10ge_priv *)arg;
 
-	if (mgp->rx_small.watchdog_needed) {
-		myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
-					mgp->small_bytes + MXGEFW_PAD, 1);
-		if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt >=
-		    myri10ge_fill_thresh)
-			mgp->rx_small.watchdog_needed = 0;
-	}
-	if (mgp->rx_big.watchdog_needed) {
-		myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 1);
-		if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt >=
-		    myri10ge_fill_thresh)
-			mgp->rx_big.watchdog_needed = 0;
-	}
-	rx_pause_cnt = ntohl(mgp->fw_stats->dropped_pause);
+	rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause);
 
-	if (mgp->tx.req != mgp->tx.done &&
-	    mgp->tx.done == mgp->watchdog_tx_done &&
-	    mgp->watchdog_tx_req != mgp->watchdog_tx_done) {
+	ss = &mgp->ss;
+	if (ss->rx_small.watchdog_needed) {
+		myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
+					mgp->small_bytes + MXGEFW_PAD, 1);
+		if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
+		    myri10ge_fill_thresh)
+			ss->rx_small.watchdog_needed = 0;
+	}
+	if (ss->rx_big.watchdog_needed) {
+		myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1);
+		if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
+		    myri10ge_fill_thresh)
+			ss->rx_big.watchdog_needed = 0;
+	}
+
+	if (ss->tx.req != ss->tx.done &&
+	    ss->tx.done == ss->watchdog_tx_done &&
+	    ss->watchdog_tx_req != ss->watchdog_tx_done) {
 		/* nic seems like it might be stuck.. */
 		if (rx_pause_cnt != mgp->watchdog_pause) {
 			if (net_ratelimit())
@@ -3005,8 +3101,8 @@
 	/* rearm timer */
 	mod_timer(&mgp->watchdog_timer,
 		  jiffies + myri10ge_watchdog_timeout * HZ);
-	mgp->watchdog_tx_done = mgp->tx.done;
-	mgp->watchdog_tx_req = mgp->tx.req;
+	ss->watchdog_tx_done = ss->tx.done;
+	ss->watchdog_tx_req = ss->tx.req;
 	mgp->watchdog_pause = rx_pause_cnt;
 }
 
@@ -3030,7 +3126,7 @@
 
 	mgp = netdev_priv(netdev);
 	mgp->dev = netdev;
-	netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight);
+	netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight);
 	mgp->pdev = pdev;
 	mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
 	mgp->pause = myri10ge_flow_control;
@@ -3076,9 +3172,9 @@
 	if (mgp->cmd == NULL)
 		goto abort_with_netdev;
 
-	mgp->fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
-					   &mgp->fw_stats_bus, GFP_KERNEL);
-	if (mgp->fw_stats == NULL)
+	mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+					   &mgp->ss.fw_stats_bus, GFP_KERNEL);
+	if (mgp->ss.fw_stats == NULL)
 		goto abort_with_cmd;
 
 	mgp->board_span = pci_resource_len(pdev, 0);
@@ -3118,12 +3214,12 @@
 		netdev->dev_addr[i] = mgp->mac_addr[i];
 
 	/* allocate rx done ring */
-	bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
-	mgp->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
-						&mgp->rx_done.bus, GFP_KERNEL);
-	if (mgp->rx_done.entry == NULL)
+	bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
+	mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+						&mgp->ss.rx_done.bus, GFP_KERNEL);
+	if (mgp->ss.rx_done.entry == NULL)
 		goto abort_with_ioremap;
-	memset(mgp->rx_done.entry, 0, bytes);
+	memset(mgp->ss.rx_done.entry, 0, bytes);
 
 	myri10ge_select_firmware(mgp);
 
@@ -3183,7 +3279,7 @@
 	}
 	dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
 		 (mgp->msi_enabled ? "MSI" : "xPIC"),
-		 netdev->irq, mgp->tx.boundary, mgp->fw_name,
+		 netdev->irq, mgp->tx_boundary, mgp->fw_name,
 		 (mgp->wc_enabled ? "Enabled" : "Disabled"));
 
 	return 0;
@@ -3195,9 +3291,9 @@
 	myri10ge_dummy_rdma(mgp, 0);
 
 abort_with_rx_done:
-	bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+	bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
 	dma_free_coherent(&pdev->dev, bytes,
-			  mgp->rx_done.entry, mgp->rx_done.bus);
+			  mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
 
 abort_with_ioremap:
 	iounmap(mgp->sram);
@@ -3207,8 +3303,8 @@
 	if (mgp->mtrr >= 0)
 		mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
 #endif
-	dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
-			  mgp->fw_stats, mgp->fw_stats_bus);
+	dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+			  mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
 
 abort_with_cmd:
 	dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
@@ -3246,9 +3342,9 @@
 	/* avoid a memory leak */
 	pci_restore_state(pdev);
 
-	bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+	bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
 	dma_free_coherent(&pdev->dev, bytes,
-			  mgp->rx_done.entry, mgp->rx_done.bus);
+			  mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
 
 	iounmap(mgp->sram);
 
@@ -3256,8 +3352,8 @@
 	if (mgp->mtrr >= 0)
 		mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
 #endif
-	dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
-			  mgp->fw_stats, mgp->fw_stats_bus);
+	dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+			  mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
 
 	dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
 			  mgp->cmd, mgp->cmd_bus);
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 58e5717..fdbeeee 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -10,7 +10,7 @@
 	__be32 low;
 };
 
-/* 4 Bytes.  8 Bytes for NDIS drivers. */
+/* 4 Bytes */
 struct mcp_slot {
 	__sum16 checksum;
 	__be16 length;
@@ -144,6 +144,7 @@
 	 * a power of 2 number of entries.  */
 
 	MXGEFW_CMD_SET_INTRQ_SIZE,	/* in bytes */
+#define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK  (1 << 31)
 
 	/* command to bring ethernet interface up.  Above parameters
 	 * (plus mtu & mac address) must have been exchanged prior
@@ -221,10 +222,14 @@
 	MXGEFW_CMD_GET_MAX_RSS_QUEUES,
 	MXGEFW_CMD_ENABLE_RSS_QUEUES,
 	/* data0 = number of slices n (0, 1, ..., n-1) to enable
-	 * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue.
+	 * data1 = interrupt mode.
+	 * 0=share one INTx/MSI, 1=use one MSI-X per queue.
 	 * If all queues share one interrupt, the driver must have set
 	 * RSS_SHARED_INTERRUPT_DMA before enabling queues.
 	 */
+#define MXGEFW_SLICE_INTR_MODE_SHARED 0
+#define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE 1
+
 	MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
 	MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
 	/* data0, data1 = bus address lsw, msw */
@@ -241,10 +246,14 @@
 	 * 0: disable rss.  nic does not distribute receive packets.
 	 * 1: enable rss.  nic distributes receive packets among queues.
 	 * data1 = hash type
-	 * 1: IPV4
-	 * 2: TCP_IPV4
-	 * 3: IPV4 | TCP_IPV4
+	 * 1: IPV4            (required by RSS)
+	 * 2: TCP_IPV4        (required by RSS)
+	 * 3: IPV4 | TCP_IPV4 (required by RSS)
+	 * 4: source port
 	 */
+#define MXGEFW_RSS_HASH_TYPE_IPV4      0x1
+#define MXGEFW_RSS_HASH_TYPE_TCP_IPV4  0x2
+#define MXGEFW_RSS_HASH_TYPE_SRC_PORT  0x4
 
 	MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
 	/* Return data = the max. size of the entire headers of a IPv6 TSO packet.
@@ -260,6 +269,8 @@
 	 * 0: Linux/FreeBSD style (NIC default)
 	 * 1: NDIS/NetBSD style
 	 */
+#define MXGEFW_TSO_MODE_LINUX  0
+#define MXGEFW_TSO_MODE_NDIS   1
 
 	MXGEFW_CMD_MDIO_READ,
 	/* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
@@ -286,6 +297,38 @@
 	/* Return data = NIC memory offset of mcp_vpump_public_global */
 	MXGEFW_CMD_RESET_VPUMP,
 	/* Resets the VPUMP state */
+
+	MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE,
+	/* data0 = mcp_slot type to use.
+	 * 0 = the default 4B mcp_slot
+	 * 1 = 8B mcp_slot_8
+	 */
+#define MXGEFW_RSS_MCP_SLOT_TYPE_MIN        0
+#define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH  1
+
+	MXGEFW_CMD_SET_THROTTLE_FACTOR,
+	/* set the throttle factor for ethp_z8e
+	 * data0 = throttle_factor
+	 * throttle_factor = 256 * pcie-raw-speed / tx_speed
+	 * tx_speed = 256 * pcie-raw-speed / throttle_factor
+	 *
+	 * For PCI-E x8: pcie-raw-speed == 16Gb/s
+	 * For PCI-E x4: pcie-raw-speed == 8Gb/s
+	 *
+	 * ex1: throttle_factor == 0x1a0 (416), tx_speed == 1.23GB/s == 9.846 Gb/s
+	 * ex2: throttle_factor == 0x200 (512), tx_speed == 1.0GB/s == 8 Gb/s
+	 *
+	 * with tx_boundary == 2048, max-throttle-factor == 8191 => min-speed == 500Mb/s
+	 * with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s
+	 */
+
+	MXGEFW_CMD_VPUMP_UP,
+	/* Allocates VPump Connection, Send Request and Zero copy buffer address tables */
+	MXGEFW_CMD_GET_VPUMP_CLK,
+	/* Get the lanai clock */
+
+	MXGEFW_CMD_GET_DCA_OFFSET,
+	/* offset of dca control for WDMAs */
 };
 
 enum myri10ge_mcp_cmd_status {
@@ -302,7 +345,8 @@
 	MXGEFW_CMD_ERROR_UNALIGNED,
 	MXGEFW_CMD_ERROR_NO_MDIO,
 	MXGEFW_CMD_ERROR_XFP_FAILURE,
-	MXGEFW_CMD_ERROR_XFP_ABSENT
+	MXGEFW_CMD_ERROR_XFP_ABSENT,
+	MXGEFW_CMD_ERROR_BAD_PCIE_LINK
 };
 
 #define MXGEFW_OLD_IRQ_DATA_LEN 40
diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
index 16a810d..07d65c2 100644
--- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
+++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
@@ -1,30 +1,6 @@
 #ifndef __MYRI10GE_MCP_GEN_HEADER_H__
 #define __MYRI10GE_MCP_GEN_HEADER_H__
 
-/* this file define a standard header used as a first entry point to
- * exchange information between firmware/driver and driver.  The
- * header structure can be anywhere in the mcp. It will usually be in
- * the .data section, because some fields needs to be initialized at
- * compile time.
- * The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must
- * contains the location of the header.
- *
- * Typically a MCP will start with the following:
- * .text
- * .space 52    ! to help catch MEMORY_INT errors
- * bt start     ! jump to real code
- * nop
- * .long _gen_mcp_header
- *
- * The source will have a definition like:
- *
- * mcp_gen_header_t gen_mcp_header = {
- * .header_length = sizeof(mcp_gen_header_t),
- * .mcp_type = MCP_TYPE_XXX,
- * .version = "something $Id: mcp_gen_header.h,v 1.2 2006/05/13 10:04:35 bgoglin Exp $",
- * .mcp_globals = (unsigned)&Globals
- * };
- */
 
 #define MCP_HEADER_PTR_OFFSET  0x3c
 
@@ -32,13 +8,14 @@
 #define MCP_TYPE_PCIE 0x70636965	/* "PCIE" pcie-only MCP */
 #define MCP_TYPE_ETH 0x45544820	/* "ETH " */
 #define MCP_TYPE_MCP0 0x4d435030	/* "MCP0" */
+#define MCP_TYPE_DFLT 0x20202020	/* "    " */
 
 struct mcp_gen_header {
 	/* the first 4 fields are filled at compile time */
 	unsigned header_length;
 	__be32 mcp_type;
 	char version[128];
-	unsigned mcp_globals;	/* pointer to mcp-type specific structure */
+	unsigned mcp_private;	/* pointer to mcp-type specific structure */
 
 	/* filled by the MCP at run-time */
 	unsigned sram_size;
@@ -53,6 +30,18 @@
 	 *
 	 * Never remove any field.  Keep everything naturally align.
 	 */
+
+	/* Specifies if the running mcp is mcp0, 1, or 2. */
+	unsigned char mcp_index;
+	unsigned char disable_rabbit;
+	unsigned char unaligned_tlp;
+	unsigned char pad1;
+	unsigned counters_addr;
+	unsigned copy_block_info;	/* for small mcps loaded with "lload -d" */
+	unsigned short handoff_id_major;	/* must be equal */
+	unsigned short handoff_id_caps;	/* bitfield: new mcp must have superset */
+	unsigned msix_table_addr;	/* start address of msix table in firmware */
+	/* 8 */
 };
 
 #endif				/* __MYRI10GE_MCP_GEN_HEADER_H__ */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 57cfd72..918f802 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -865,7 +865,6 @@
 	return 0;
 }
 
-
 static int link_status_10g_serdes(struct niu *np, int *link_up_p)
 {
 	unsigned long flags;
@@ -900,7 +899,6 @@
 	return 0;
 }
 
-
 static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
 {
 	struct niu_link_config *lp = &np->link_config;
@@ -957,7 +955,6 @@
 	return err;
 }
 
-
 static int bcm8704_reset(struct niu *np)
 {
 	int err, limit;
@@ -1357,8 +1354,6 @@
 	return 0;
 }
 
-
-
 static int xcvr_init_1g_rgmii(struct niu *np)
 {
 	int err;
@@ -1419,7 +1414,6 @@
 	return 0;
 }
 
-
 static int mii_init_common(struct niu *np)
 {
 	struct niu_link_config *lp = &np->link_config;
@@ -7008,31 +7002,20 @@
 	return 0;
 }
 
-/* niu board models have a trailing dash version incremented
- * with HW rev change. Need to ingnore the  dash version while
- * checking for match
- *
- * for example, for the 10G card the current vpd.board_model
- * is 501-5283-04, of which -04 is the  dash version and have
- * to be ignored
- */
-static int niu_board_model_match(struct niu *np, const char *model)
-{
-	return !strncmp(np->vpd.board_model, model, strlen(model));
-}
-
 static int niu_pci_vpd_get_nports(struct niu *np)
 {
 	int ports = 0;
 
-	if ((niu_board_model_match(np, NIU_QGC_LP_BM_STR)) ||
-	    (niu_board_model_match(np, NIU_QGC_PEM_BM_STR)) ||
-	    (niu_board_model_match(np, NIU_ALONSO_BM_STR))) {
+	if ((!strcmp(np->vpd.model, NIU_QGC_LP_MDL_STR)) ||
+	    (!strcmp(np->vpd.model, NIU_QGC_PEM_MDL_STR)) ||
+	    (!strcmp(np->vpd.model, NIU_MARAMBA_MDL_STR)) ||
+	    (!strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) ||
+	    (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR))) {
 		ports = 4;
-	} else if ((niu_board_model_match(np, NIU_2XGF_LP_BM_STR)) ||
-		   (niu_board_model_match(np, NIU_2XGF_PEM_BM_STR)) ||
-		   (niu_board_model_match(np, NIU_FOXXY_BM_STR)) ||
-		   (niu_board_model_match(np, NIU_2XGF_MRVL_BM_STR))) {
+	} else if ((!strcmp(np->vpd.model, NIU_2XGF_LP_MDL_STR)) ||
+		   (!strcmp(np->vpd.model, NIU_2XGF_PEM_MDL_STR)) ||
+		   (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) ||
+		   (!strcmp(np->vpd.model, NIU_2XGF_MRVL_MDL_STR))) {
 		ports = 2;
 	}
 
@@ -7053,8 +7036,8 @@
 		return;
 	}
 
-	if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
-	    !strcmp(np->vpd.model, "SUNW,CP3260")) {
+	if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+	    !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
 		np->flags |= NIU_FLAGS_10G;
 		np->flags &= ~NIU_FLAGS_FIBER;
 		np->flags |= NIU_FLAGS_XCVR_SERDES;
@@ -7065,7 +7048,7 @@
 		}
 		if (np->flags & NIU_FLAGS_10G)
 			 np->mac_xcvr = MAC_XCVR_XPCS;
-	} else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+	} else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
 		np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
 			      NIU_FLAGS_HOTPLUG_PHY);
 	} else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
@@ -7541,8 +7524,8 @@
 	u32 val;
 	int err;
 
-	if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
-	    !strcmp(np->vpd.model, "SUNW,CP3260")) {
+	if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+	    !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
 		num_10g = 0;
 		num_1g = 2;
 		parent->plat_type = PLAT_TYPE_ATCA_CP3220;
@@ -7551,7 +7534,7 @@
 		       phy_encode(PORT_TYPE_1G, 1) |
 		       phy_encode(PORT_TYPE_1G, 2) |
 		       phy_encode(PORT_TYPE_1G, 3));
-	} else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+	} else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
 		num_10g = 2;
 		num_1g = 0;
 		parent->num_ports = 2;
@@ -7946,6 +7929,7 @@
 	struct device_node *dp;
 	const char *phy_type;
 	const u8 *mac_addr;
+	const char *model;
 	int prop_len;
 
 	if (np->parent->plat_type == PLAT_TYPE_NIU)
@@ -8000,6 +7984,11 @@
 
 	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
 
+	model = of_get_property(dp, "model", &prop_len);
+
+	if (model)
+		strcpy(np->vpd.model, model);
+
 	return 0;
 #else
 	return -EINVAL;
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 97ffbe1..12fd570 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -2946,6 +2946,15 @@
 #define	NIU_ALONSO_BM_STR	"373-0202"
 #define	NIU_FOXXY_BM_STR	"501-7961"
 #define	NIU_2XGF_MRVL_BM_STR	"SK-6E82"
+#define	NIU_QGC_LP_MDL_STR	"SUNW,pcie-qgc"
+#define	NIU_2XGF_LP_MDL_STR	"SUNW,pcie-2xgf"
+#define	NIU_QGC_PEM_MDL_STR	"SUNW,pcie-qgc-pem"
+#define	NIU_2XGF_PEM_MDL_STR	"SUNW,pcie-2xgf-pem"
+#define	NIU_ALONSO_MDL_STR	"SUNW,CP3220"
+#define	NIU_KIMI_MDL_STR	"SUNW,CP3260"
+#define	NIU_MARAMBA_MDL_STR	"SUNW,pcie-neptune"
+#define	NIU_FOXXY_MDL_STR	"SUNW,pcie-rfem"
+#define	NIU_2XGF_MRVL_MDL_STR	"SysKonnect,pcie-2xgf"
 
 #define NIU_VPD_MIN_MAJOR	3
 #define NIU_VPD_MIN_MINOR	4
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index d3207c0..1f4ca2b 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2458,6 +2458,7 @@
 
 out3:
 	atomic_dec(&ppp_unit_count);
+	unregister_netdev(dev);
 out2:
 	mutex_unlock(&all_ppp_mutex);
 	free_netdev(dev);
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 244d783..79359919 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -1621,9 +1621,16 @@
 end:
 	release_sock(sk);
 
-	if (error != 0)
-		PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
-		       "%s: connect failed: %d\n", session->name, error);
+	if (error != 0) {
+		if (session)
+			PRINTK(session->debug,
+				PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+				"%s: connect failed: %d\n",
+				session->name, error);
+		else
+			PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+				"connect failed: %d\n", error);
+	}
 
 	return error;
 }
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 0d32123..1dae1f2 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -2474,6 +2474,8 @@
 
 	pr_debug("%s: <-\n", __func__);
 
+	free_page((unsigned long)wl->buf);
+
 	pr_debug("%s: destroy queues\n", __func__);
 	destroy_workqueue(wl->eurus_cmd_queue);
 	destroy_workqueue(wl->event_queue);
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 0f02344..1d2daee 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -1,5 +1,5 @@
 sfc-y			+= efx.o falcon.o tx.o rx.o falcon_xmac.o \
-			   i2c-direct.o ethtool.o xfp_phy.o mdio_10g.o \
-			   tenxpress.o boards.o sfe4001.o
+			   i2c-direct.o selftest.o ethtool.o xfp_phy.o \
+			   mdio_10g.o tenxpress.o boards.o sfe4001.o
 
 obj-$(CONFIG_SFC)	+= sfc.o
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
index f56341d..695764d 100644
--- a/drivers/net/sfc/boards.h
+++ b/drivers/net/sfc/boards.h
@@ -22,5 +22,7 @@
 extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
 extern int sfe4001_poweron(struct efx_nic *efx);
 extern void sfe4001_poweroff(struct efx_nic *efx);
+/* Are we putting the PHY into flash config mode */
+extern unsigned int sfe4001_phy_flash_cfg;
 
 #endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 59edcf7..418f2e5 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1873,6 +1873,7 @@
 		tx_queue->queue = i;
 		tx_queue->buffer = NULL;
 		tx_queue->channel = &efx->channel[0]; /* for safety */
+		tx_queue->tso_headers_free = NULL;
 	}
 	for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
 		rx_queue = &efx->rx_queue[i];
@@ -2071,7 +2072,8 @@
 	net_dev = alloc_etherdev(sizeof(*efx));
 	if (!net_dev)
 		return -ENOMEM;
-	net_dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
+	net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG |
+			      NETIF_F_HIGHDMA | NETIF_F_TSO);
 	if (lro)
 		net_dev->features |= NETIF_F_LRO;
 	efx = net_dev->priv;
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
index 43663a4..c53290d 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/sfc/enum.h
@@ -10,6 +10,55 @@
 #ifndef EFX_ENUM_H
 #define EFX_ENUM_H
 
+/**
+ * enum efx_loopback_mode - loopback modes
+ * @LOOPBACK_NONE: no loopback
+ * @LOOPBACK_XGMII: loopback within MAC at XGMII level
+ * @LOOPBACK_XGXS: loopback within MAC at XGXS level
+ * @LOOPBACK_XAUI: loopback within MAC at XAUI level
+ * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
+ * @LOOPBACK_PCS: loopback within PHY at PCS level
+ * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
+ * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
+ */
+/* Please keep in order and up-to-date w.r.t the following two #defines */
+enum efx_loopback_mode {
+	LOOPBACK_NONE = 0,
+	LOOPBACK_MAC = 1,
+	LOOPBACK_XGMII = 2,
+	LOOPBACK_XGXS = 3,
+	LOOPBACK_XAUI = 4,
+	LOOPBACK_PHY = 5,
+	LOOPBACK_PHYXS = 6,
+	LOOPBACK_PCS = 7,
+	LOOPBACK_PMAPMD = 8,
+	LOOPBACK_NETWORK = 9,
+	LOOPBACK_MAX
+};
+
+#define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
+
+extern const char *efx_loopback_mode_names[];
+#define LOOPBACK_MODE_NAME(mode)			\
+	STRING_TABLE_LOOKUP(mode, efx_loopback_mode)
+#define LOOPBACK_MODE(efx)				\
+	LOOPBACK_MODE_NAME(efx->loopback_mode)
+
+/* These loopbacks occur within the controller */
+#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
+				(1 << LOOPBACK_XGXS) | \
+				(1 << LOOPBACK_XAUI))
+
+#define LOOPBACK_MASK(_efx)			\
+	(1 << (_efx)->loopback_mode)
+
+#define LOOPBACK_INTERNAL(_efx)						\
+	((LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)) ? 1 : 0)
+
+#define LOOPBACK_OUT_OF(_from, _to, _mask)		\
+	(((LOOPBACK_MASK(_from) & (_mask)) &&		\
+	  ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0)
+
 /*****************************************************************************/
 
 /**
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index ad541ba..e2c75d1 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -12,12 +12,26 @@
 #include <linux/ethtool.h>
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
+#include "selftest.h"
 #include "efx.h"
 #include "ethtool.h"
 #include "falcon.h"
 #include "gmii.h"
 #include "mac.h"
 
+const char *efx_loopback_mode_names[] = {
+	[LOOPBACK_NONE]		= "NONE",
+	[LOOPBACK_MAC]		= "MAC",
+	[LOOPBACK_XGMII]	= "XGMII",
+	[LOOPBACK_XGXS]		= "XGXS",
+	[LOOPBACK_XAUI] 	= "XAUI",
+	[LOOPBACK_PHY]		= "PHY",
+	[LOOPBACK_PHYXS]	= "PHY(XS)",
+	[LOOPBACK_PCS]	 	= "PHY(PCS)",
+	[LOOPBACK_PMAPMD]	= "PHY(PMAPMD)",
+	[LOOPBACK_NETWORK]	= "NETWORK",
+};
+
 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
 
 struct ethtool_string {
@@ -217,23 +231,179 @@
 	strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
 }
 
+/**
+ * efx_fill_test - fill in an individual self-test entry
+ * @test_index:		Index of the test
+ * @strings:		Ethtool strings, or %NULL
+ * @data:		Ethtool test results, or %NULL
+ * @test:		Pointer to test result (used only if data != %NULL)
+ * @unit_format:	Unit name format (e.g. "channel\%d")
+ * @unit_id:		Unit id (e.g. 0 for "channel0")
+ * @test_format:	Test name format (e.g. "loopback.\%s.tx.sent")
+ * @test_id:		Test id (e.g. "PHY" for "loopback.PHY.tx_sent")
+ *
+ * Fill in an individual self-test entry.
+ */
+static void efx_fill_test(unsigned int test_index,
+			  struct ethtool_string *strings, u64 *data,
+			  int *test, const char *unit_format, int unit_id,
+			  const char *test_format, const char *test_id)
+{
+	struct ethtool_string unit_str, test_str;
+
+	/* Fill data value, if applicable */
+	if (data)
+		data[test_index] = *test;
+
+	/* Fill string, if applicable */
+	if (strings) {
+		snprintf(unit_str.name, sizeof(unit_str.name),
+			 unit_format, unit_id);
+		snprintf(test_str.name, sizeof(test_str.name),
+			 test_format, test_id);
+		snprintf(strings[test_index].name,
+			 sizeof(strings[test_index].name),
+			 "%-9s%-17s", unit_str.name, test_str.name);
+	}
+}
+
+#define EFX_PORT_NAME "port%d", 0
+#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel
+#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
+#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
+#define EFX_LOOPBACK_NAME(_mode, _counter)			\
+	"loopback.%s." _counter, LOOPBACK_MODE_NAME(mode)
+
+/**
+ * efx_fill_loopback_test - fill in a block of loopback self-test entries
+ * @efx:		Efx NIC
+ * @lb_tests:		Efx loopback self-test results structure
+ * @mode:		Loopback test mode
+ * @test_index:		Starting index of the test
+ * @strings:		Ethtool strings, or %NULL
+ * @data:		Ethtool test results, or %NULL
+ */
+static int efx_fill_loopback_test(struct efx_nic *efx,
+				  struct efx_loopback_self_tests *lb_tests,
+				  enum efx_loopback_mode mode,
+				  unsigned int test_index,
+				  struct ethtool_string *strings, u64 *data)
+{
+	struct efx_tx_queue *tx_queue;
+
+	efx_for_each_tx_queue(tx_queue, efx) {
+		efx_fill_test(test_index++, strings, data,
+			      &lb_tests->tx_sent[tx_queue->queue],
+			      EFX_TX_QUEUE_NAME(tx_queue),
+			      EFX_LOOPBACK_NAME(mode, "tx_sent"));
+		efx_fill_test(test_index++, strings, data,
+			      &lb_tests->tx_done[tx_queue->queue],
+			      EFX_TX_QUEUE_NAME(tx_queue),
+			      EFX_LOOPBACK_NAME(mode, "tx_done"));
+	}
+	efx_fill_test(test_index++, strings, data,
+		      &lb_tests->rx_good,
+		      EFX_PORT_NAME,
+		      EFX_LOOPBACK_NAME(mode, "rx_good"));
+	efx_fill_test(test_index++, strings, data,
+		      &lb_tests->rx_bad,
+		      EFX_PORT_NAME,
+		      EFX_LOOPBACK_NAME(mode, "rx_bad"));
+
+	return test_index;
+}
+
+/**
+ * efx_ethtool_fill_self_tests - get self-test details
+ * @efx:		Efx NIC
+ * @tests:		Efx self-test results structure, or %NULL
+ * @strings:		Ethtool strings, or %NULL
+ * @data:		Ethtool test results, or %NULL
+ */
+static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
+				       struct efx_self_tests *tests,
+				       struct ethtool_string *strings,
+				       u64 *data)
+{
+	struct efx_channel *channel;
+	unsigned int n = 0;
+	enum efx_loopback_mode mode;
+
+	/* Interrupt */
+	efx_fill_test(n++, strings, data, &tests->interrupt,
+		      "core", 0, "interrupt", NULL);
+
+	/* Event queues */
+	efx_for_each_channel(channel, efx) {
+		efx_fill_test(n++, strings, data,
+			      &tests->eventq_dma[channel->channel],
+			      EFX_CHANNEL_NAME(channel),
+			      "eventq.dma", NULL);
+		efx_fill_test(n++, strings, data,
+			      &tests->eventq_int[channel->channel],
+			      EFX_CHANNEL_NAME(channel),
+			      "eventq.int", NULL);
+		efx_fill_test(n++, strings, data,
+			      &tests->eventq_poll[channel->channel],
+			      EFX_CHANNEL_NAME(channel),
+			      "eventq.poll", NULL);
+	}
+
+	/* PHY presence */
+	efx_fill_test(n++, strings, data, &tests->phy_ok,
+		      EFX_PORT_NAME, "phy_ok", NULL);
+
+	/* Loopback tests */
+	efx_fill_test(n++, strings, data, &tests->loopback_speed,
+		      EFX_PORT_NAME, "loopback.speed", NULL);
+	efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
+		      EFX_PORT_NAME, "loopback.full_duplex", NULL);
+	for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+		if (!(efx->loopback_modes & (1 << mode)))
+			continue;
+		n = efx_fill_loopback_test(efx,
+					   &tests->loopback[mode], mode, n,
+					   strings, data);
+	}
+
+	return n;
+}
+
 static int efx_ethtool_get_stats_count(struct net_device *net_dev)
 {
 	return EFX_ETHTOOL_NUM_STATS;
 }
 
+static int efx_ethtool_self_test_count(struct net_device *net_dev)
+{
+	struct efx_nic *efx = net_dev->priv;
+
+	return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
+}
+
 static void efx_ethtool_get_strings(struct net_device *net_dev,
 				    u32 string_set, u8 *strings)
 {
+	struct efx_nic *efx = net_dev->priv;
 	struct ethtool_string *ethtool_strings =
 		(struct ethtool_string *)strings;
 	int i;
 
-	if (string_set == ETH_SS_STATS)
+	switch (string_set) {
+	case ETH_SS_STATS:
 		for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
 			strncpy(ethtool_strings[i].name,
 				efx_ethtool_stats[i].name,
 				sizeof(ethtool_strings[i].name));
+		break;
+	case ETH_SS_TEST:
+		efx_ethtool_fill_self_tests(efx, NULL,
+					    ethtool_strings, NULL);
+		break;
+	default:
+		/* No other string sets */
+		break;
+	}
 }
 
 static void efx_ethtool_get_stats(struct net_device *net_dev,
@@ -272,6 +442,22 @@
 	}
 }
 
+static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
+{
+	int rc;
+
+	/* Our TSO requires TX checksumming, so force TX checksumming
+	 * on when TSO is enabled.
+	 */
+	if (enable) {
+		rc = efx_ethtool_set_tx_csum(net_dev, 1);
+		if (rc)
+			return rc;
+	}
+
+	return ethtool_op_set_tso(net_dev, enable);
+}
+
 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
 {
 	struct efx_nic *efx = net_dev->priv;
@@ -283,6 +469,15 @@
 
 	efx_flush_queues(efx);
 
+	/* Our TSO requires TX checksumming, so disable TSO when
+	 * checksumming is disabled
+	 */
+	if (!enable) {
+		rc = efx_ethtool_set_tso(net_dev, 0);
+		if (rc)
+			return rc;
+	}
+
 	return 0;
 }
 
@@ -305,6 +500,64 @@
 	return efx->rx_checksum_enabled;
 }
 
+static void efx_ethtool_self_test(struct net_device *net_dev,
+				  struct ethtool_test *test, u64 *data)
+{
+	struct efx_nic *efx = net_dev->priv;
+	struct efx_self_tests efx_tests;
+	int offline, already_up;
+	int rc;
+
+	ASSERT_RTNL();
+	if (efx->state != STATE_RUNNING) {
+		rc = -EIO;
+		goto fail1;
+	}
+
+	/* We need rx buffers and interrupts. */
+	already_up = (efx->net_dev->flags & IFF_UP);
+	if (!already_up) {
+		rc = dev_open(efx->net_dev);
+		if (rc) {
+			EFX_ERR(efx, "failed opening device.\n");
+			goto fail2;
+		}
+	}
+
+	memset(&efx_tests, 0, sizeof(efx_tests));
+	offline = (test->flags & ETH_TEST_FL_OFFLINE);
+
+	/* Perform online self tests first */
+	rc = efx_online_test(efx, &efx_tests);
+	if (rc)
+		goto out;
+
+	/* Perform offline tests only if online tests passed */
+	if (offline) {
+		/* Stop the kernel from sending packets during the test. */
+		efx_stop_queue(efx);
+		rc = efx_flush_queues(efx);
+		if (!rc)
+			rc = efx_offline_test(efx, &efx_tests,
+					      efx->loopback_modes);
+		efx_wake_queue(efx);
+	}
+
+ out:
+	if (!already_up)
+		dev_close(efx->net_dev);
+
+	EFX_LOG(efx, "%s all %sline self-tests\n",
+		rc == 0 ? "passed" : "failed", offline ? "off" : "on");
+
+ fail2:
+ fail1:
+	/* Fill ethtool results structures */
+	efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
+	if (rc)
+		test->flags |= ETH_TEST_FL_FAILED;
+}
+
 /* Restart autonegotiation */
 static int efx_ethtool_nway_reset(struct net_device *net_dev)
 {
@@ -451,8 +704,12 @@
 	.set_tx_csum		= efx_ethtool_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= efx_ethtool_set_tso,
 	.get_flags		= ethtool_op_get_flags,
 	.set_flags		= ethtool_op_set_flags,
+	.self_test_count	= efx_ethtool_self_test_count,
+	.self_test		= efx_ethtool_self_test,
 	.get_strings		= efx_ethtool_get_strings,
 	.phys_id		= efx_ethtool_phys_id,
 	.get_stats_count	= efx_ethtool_get_stats_count,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 46db549..b57cc68 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1129,6 +1129,7 @@
 	case RX_RECOVERY_EV_DECODE:
 		EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
 			"Resetting.\n", channel->channel);
+		atomic_inc(&efx->rx_reset);
 		efx_schedule_reset(efx,
 				   EFX_WORKAROUND_6555(efx) ?
 				   RESET_TYPE_RX_RECOVERY :
@@ -1731,7 +1732,8 @@
 	efx_oword_t temp;
 	int count;
 
-	if (FALCON_REV(efx) < FALCON_REV_B0)
+	if ((FALCON_REV(efx) < FALCON_REV_B0) ||
+	    (efx->loopback_mode != LOOPBACK_NONE))
 		return;
 
 	falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
@@ -2091,6 +2093,8 @@
 			efx->phy_type);
 		return -1;
 	}
+
+	efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks;
 	return 0;
 }
 
@@ -2468,14 +2472,12 @@
  fail5:
 	falcon_free_buffer(efx, &efx->irq_status);
  fail4:
-	/* fall-thru */
  fail3:
 	if (nic_data->pci_dev2) {
 		pci_dev_put(nic_data->pci_dev2);
 		nic_data->pci_dev2 = NULL;
 	}
  fail2:
-	/* fall-thru */
  fail1:
 	kfree(efx->nic_data);
 	return rc;
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
index 0485a63..06e2d68 100644
--- a/drivers/net/sfc/falcon_hwdefs.h
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -636,6 +636,14 @@
 #define XX_HIDRVA_WIDTH 1
 #define XX_LODRVA_LBN 8
 #define XX_LODRVA_WIDTH 1
+#define XX_LPBKD_LBN 3
+#define XX_LPBKD_WIDTH 1
+#define XX_LPBKC_LBN 2
+#define XX_LPBKC_WIDTH 1
+#define XX_LPBKB_LBN 1
+#define XX_LPBKB_WIDTH 1
+#define XX_LPBKA_LBN 0
+#define XX_LPBKA_WIDTH 1
 
 #define XX_TXDRV_CTL_REG_MAC 0x12
 #define XX_DEQD_LBN 28
@@ -656,8 +664,14 @@
 #define XX_DTXA_WIDTH 4
 
 /* XAUI XGXS core status register */
-#define XX_FORCE_SIG_DECODE_FORCED 0xff
 #define XX_CORE_STAT_REG_MAC 0x16
+#define XX_FORCE_SIG_LBN 24
+#define XX_FORCE_SIG_WIDTH 8
+#define XX_FORCE_SIG_DECODE_FORCED 0xff
+#define XX_XGXS_LB_EN_LBN 23
+#define XX_XGXS_LB_EN_WIDTH 1
+#define XX_XGMII_LB_EN_LBN 22
+#define XX_XGMII_LB_EN_WIDTH 1
 #define XX_ALIGN_DONE_LBN 20
 #define XX_ALIGN_DONE_WIDTH 1
 #define XX_SYNC_STAT_LBN 16
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index aa7521b..a74b793 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -32,7 +32,7 @@
 	(FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
 
 void falcon_xmac_writel(struct efx_nic *efx,
-			efx_dword_t *value, unsigned int mac_reg)
+			 efx_dword_t *value, unsigned int mac_reg)
 {
 	efx_oword_t temp;
 
@@ -69,6 +69,10 @@
 		udelay(10);
 	}
 
+	/* This often fails when DSP is disabled, ignore it */
+	if (sfe4001_phy_flash_cfg != 0)
+		return 0;
+
 	EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
 	return -ETIMEDOUT;
 }
@@ -223,7 +227,7 @@
 	/* The ISR latches, so clear it and re-read */
 	falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
 	falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
-	
+
 	if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
 	    EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
 		EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
@@ -237,7 +241,7 @@
 {
 	efx_dword_t reg;
 
-	if (FALCON_REV(efx) < FALCON_REV_B0)
+	if ((FALCON_REV(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
 		return;
 
 	/* Flush the ISR */
@@ -284,6 +288,9 @@
 	efx_dword_t reg;
 	int align_done, sync_status, link_ok = 0;
 
+	if (LOOPBACK_INTERNAL(efx))
+		return 1;
+
 	/* Read link status */
 	falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
 
@@ -374,6 +381,61 @@
 	falcon_xmac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
 }
 
+static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
+{
+	efx_dword_t reg;
+	int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0;
+	int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0;
+	int xgmii_loopback =
+		(efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
+
+	/* XGXS block is flaky and will need to be reset if moving
+	 * into our out of XGMII, XGXS or XAUI loopbacks. */
+	if (EFX_WORKAROUND_5147(efx)) {
+		int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
+		int reset_xgxs;
+
+		falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+		old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN);
+		old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN);
+
+		falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
+		old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA);
+
+		/* The PHY driver may have turned XAUI off */
+		reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
+			      (xaui_loopback != old_xaui_loopback) ||
+			      (xgmii_loopback != old_xgmii_loopback));
+		if (reset_xgxs) {
+			falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
+			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
+			falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+			udelay(1);
+			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0);
+			EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0);
+			falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+			udelay(1);
+		}
+	}
+
+	falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+	EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG,
+			    (xgxs_loopback || xaui_loopback) ?
+			    XX_FORCE_SIG_DECODE_FORCED : 0);
+	EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
+	EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
+	falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+	falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
+	EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
+	EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
+	EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
+	EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
+	falcon_xmac_writel(efx, &reg, XX_SD_CTL_REG_MAC);
+}
+
+
 /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
  * to come back up. Bash it until it comes back up */
 static int falcon_check_xaui_link_up(struct efx_nic *efx)
@@ -382,7 +444,8 @@
 	tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
 	max_tries = tries;
 
-	if (efx->phy_type == PHY_TYPE_NONE)
+	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+	    (efx->phy_type == PHY_TYPE_NONE))
 		return 0;
 
 	while (tries) {
@@ -408,8 +471,13 @@
 	falcon_mask_status_intr(efx, 0);
 
 	falcon_deconfigure_mac_wrapper(efx);
+
+	efx->tx_disabled = LOOPBACK_INTERNAL(efx);
 	efx->phy_op->reconfigure(efx);
+
+	falcon_reconfigure_xgxs_core(efx);
 	falcon_reconfigure_xmac_core(efx);
+
 	falcon_reconfigure_mac_wrapper(efx);
 
 	/* Ensure XAUI link is up */
@@ -491,13 +559,15 @@
 		(mac_stats->rx_bytes - mac_stats->rx_good_bytes);
 }
 
-#define EFX_XAUI_RETRAIN_MAX 8
-
 int falcon_check_xmac(struct efx_nic *efx)
 {
 	unsigned xaui_link_ok;
 	int rc;
 
+	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+	    (efx->phy_type == PHY_TYPE_NONE))
+		return 0;
+
 	falcon_mask_status_intr(efx, 0);
 	xaui_link_ok = falcon_xaui_link_ok(efx);
 
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index dc06bb0..c4f540e 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -44,6 +44,9 @@
 	int status;
 	int phy_id = efx->mii.phy_id;
 
+	if (LOOPBACK_INTERNAL(efx))
+		return 0;
+
 	/* Read MMD STATUS2 to check it is responding. */
 	status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
 	if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
@@ -164,6 +167,22 @@
 	int mmd = 0;
 	int good;
 
+	/* If the port is in loopback, then we should only consider a subset
+	 * of mmd's */
+	if (LOOPBACK_INTERNAL(efx))
+		return 1;
+	else if (efx->loopback_mode == LOOPBACK_NETWORK)
+		return 0;
+	else if (efx->loopback_mode == LOOPBACK_PHYXS)
+		mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
+			      MDIO_MMDREG_DEVS0_PCS |
+			      MDIO_MMDREG_DEVS0_PMAPMD);
+	else if (efx->loopback_mode == LOOPBACK_PCS)
+		mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS |
+			      MDIO_MMDREG_DEVS0_PMAPMD);
+	else if (efx->loopback_mode == LOOPBACK_PMAPMD)
+		mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD;
+
 	while (mmd_mask) {
 		if (mmd_mask & 1) {
 			/* Double reads because link state is latched, and a
@@ -182,6 +201,65 @@
 	return ok;
 }
 
+void mdio_clause45_transmit_disable(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+	int ctrl1, ctrl2;
+
+	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					   MDIO_MMDREG_TXDIS);
+	if (efx->tx_disabled)
+		ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
+	else
+		ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
+	if (ctrl1 != ctrl2)
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+				    MDIO_MMDREG_TXDIS, ctrl2);
+}
+
+void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+	int ctrl1, ctrl2;
+
+	/* Handle (with debouncing) PMA/PMD loopback */
+	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					   MDIO_MMDREG_CTRL1);
+
+	if (efx->loopback_mode == LOOPBACK_PMAPMD)
+		ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
+	else
+		ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
+
+	if (ctrl1 != ctrl2)
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+				    MDIO_MMDREG_CTRL1, ctrl2);
+
+	/* Handle (with debouncing) PCS loopback */
+	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
+					   MDIO_MMDREG_CTRL1);
+	if (efx->loopback_mode == LOOPBACK_PCS)
+		ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+	else
+		ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+
+	if (ctrl1 != ctrl2)
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS,
+				    MDIO_MMDREG_CTRL1, ctrl2);
+
+	/* Handle (with debouncing) PHYXS network loopback */
+	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
+					   MDIO_MMDREG_CTRL1);
+	if (efx->loopback_mode == LOOPBACK_NETWORK)
+		ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+	else
+		ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+
+	if (ctrl1 != ctrl2)
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
+				    MDIO_MMDREG_CTRL1, ctrl2);
+}
+
 /**
  * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
  * @efx:		Efx NIC
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 2214b6d..cb99f3f 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -44,11 +44,16 @@
 #define MDIO_MMDREG_DEVS1	(6)
 #define MDIO_MMDREG_CTRL2	(7)
 #define MDIO_MMDREG_STAT2	(8)
+#define MDIO_MMDREG_TXDIS	(9)
 
 /* Bits in MMDREG_CTRL1 */
 /* Reset */
 #define MDIO_MMDREG_CTRL1_RESET_LBN	(15)
 #define MDIO_MMDREG_CTRL1_RESET_WIDTH	(1)
+/* Loopback */
+/* Loopback bit for WIS, PCS, PHYSX and DTEXS */
+#define MDIO_MMDREG_CTRL1_LBACK_LBN	(14)
+#define MDIO_MMDREG_CTRL1_LBACK_WIDTH	(1)
 
 /* Bits in MMDREG_STAT1 */
 #define MDIO_MMDREG_STAT1_FAULT_LBN	(7)
@@ -56,6 +61,9 @@
 /* Link state */
 #define MDIO_MMDREG_STAT1_LINK_LBN	(2)
 #define MDIO_MMDREG_STAT1_LINK_WIDTH	(1)
+/* Low power ability */
+#define MDIO_MMDREG_STAT1_LPABLE_LBN	(1)
+#define MDIO_MMDREG_STAT1_LPABLE_WIDTH	(1)
 
 /* Bits in ID reg */
 #define MDIO_ID_REV(_id32)	(_id32 & 0xf)
@@ -76,6 +84,14 @@
 #define MDIO_MMDREG_STAT2_PRESENT_LBN	(14)
 #define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
 
+/* Bits in MMDREG_TXDIS */
+#define MDIO_MMDREG_TXDIS_GLOBAL_LBN    (0)
+#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH  (1)
+
+/* MMD-specific bits, ordered by MMD, then register */
+#define MDIO_PMAPMD_CTRL1_LBACK_LBN	(0)
+#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH	(1)
+
 /* PMA type (4 bits) */
 #define MDIO_PMAPMD_CTRL2_10G_CX4	(0x0)
 #define MDIO_PMAPMD_CTRL2_10G_EW	(0x1)
@@ -95,7 +111,7 @@
 #define MDIO_PMAPMD_CTRL2_10_BT		(0xf)
 #define MDIO_PMAPMD_CTRL2_TYPE_MASK	(0xf)
 
-/* /\* PHY XGXS lane state *\/ */
+/* PHY XGXS lane state */
 #define MDIO_PHYXS_LANE_STATE		(0x18)
 #define MDIO_PHYXS_LANE_ALIGNED_LBN	(12)
 
@@ -217,6 +233,12 @@
 extern int mdio_clause45_links_ok(struct efx_nic *efx,
 				  unsigned int mmd_mask);
 
+/* Generic transmit disable support though PMAPMD */
+extern void mdio_clause45_transmit_disable(struct efx_nic *efx);
+
+/* Generic part of reconfigure: set/clear loopback bits */
+extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
+
 /* Read (some of) the PHY settings over MDIO */
 extern void mdio_clause45_get_settings(struct efx_nic *efx,
 				       struct ethtool_cmd *ecmd);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index c505482..59f261b 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -134,6 +134,8 @@
  *	Set only on the final fragment of a packet; %NULL for all other
  *	fragments.  When this fragment completes, then we can free this
  *	skb.
+ * @tsoh: The associated TSO header structure, or %NULL if this
+ *	buffer is not a TSO header.
  * @dma_addr: DMA address of the fragment.
  * @len: Length of this fragment.
  *	This field is zero when the queue slot is empty.
@@ -144,6 +146,7 @@
  */
 struct efx_tx_buffer {
 	const struct sk_buff *skb;
+	struct efx_tso_header *tsoh;
 	dma_addr_t dma_addr;
 	unsigned short len;
 	unsigned char continuation;
@@ -187,6 +190,13 @@
  *	variable indicates that the queue is full.  This is to
  *	avoid cache-line ping-pong between the xmit path and the
  *	completion path.
+ * @tso_headers_free: A list of TSO headers allocated for this TX queue
+ *	that are not in use, and so available for new TSO sends. The list
+ *	is protected by the TX queue lock.
+ * @tso_bursts: Number of times TSO xmit invoked by kernel
+ * @tso_long_headers: Number of packets with headers too long for standard
+ *	blocks
+ * @tso_packets: Number of packets via the TSO xmit path
  */
 struct efx_tx_queue {
 	/* Members which don't change on the fast path */
@@ -206,6 +216,10 @@
 	unsigned int insert_count ____cacheline_aligned_in_smp;
 	unsigned int write_count;
 	unsigned int old_read_count;
+	struct efx_tso_header *tso_headers_free;
+	unsigned int tso_bursts;
+	unsigned int tso_long_headers;
+	unsigned int tso_packets;
 };
 
 /**
@@ -434,6 +448,9 @@
 	struct efx_blinker blinker;
 };
 
+#define STRING_TABLE_LOOKUP(val, member)	\
+	member ## _names[val]
+
 enum efx_int_mode {
 	/* Be careful if altering to correct macro below */
 	EFX_INT_MODE_MSIX = 0,
@@ -506,6 +523,7 @@
  * @check_hw: Check hardware
  * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
  * @mmds: MMD presence mask
+ * @loopbacks: Supported loopback modes mask
  */
 struct efx_phy_operations {
 	int (*init) (struct efx_nic *efx);
@@ -515,6 +533,7 @@
 	int (*check_hw) (struct efx_nic *efx);
 	void (*reset_xaui) (struct efx_nic *efx);
 	int mmds;
+	unsigned loopbacks;
 };
 
 /*
@@ -653,7 +672,6 @@
  * @phy_op: PHY interface
  * @phy_data: PHY private data (including PHY-specific stats)
  * @mii: PHY interface
- * @phy_powered: PHY power state
  * @tx_disabled: PHY transmitter turned off
  * @link_up: Link status
  * @link_options: Link options (MII/GMII format)
@@ -662,6 +680,9 @@
  * @multicast_hash: Multicast hash table
  * @flow_control: Flow control flags - separate RX/TX so can't use link_options
  * @reconfigure_work: work item for dealing with PHY events
+ * @loopback_mode: Loopback status
+ * @loopback_modes: Supported loopback mode bitmask
+ * @loopback_selftest: Offline self-test private state
  *
  * The @priv field of the corresponding &struct net_device points to
  * this.
@@ -721,6 +742,7 @@
 	struct efx_phy_operations *phy_op;
 	void *phy_data;
 	struct mii_if_info mii;
+	unsigned tx_disabled;
 
 	int link_up;
 	unsigned int link_options;
@@ -732,6 +754,10 @@
 	struct work_struct reconfigure_work;
 
 	atomic_t rx_reset;
+	enum efx_loopback_mode loopback_mode;
+	unsigned int loopback_modes;
+
+	void *loopback_selftest;
 };
 
 /**
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 551299b..6706223 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -19,6 +19,7 @@
 #include "rx.h"
 #include "efx.h"
 #include "falcon.h"
+#include "selftest.h"
 #include "workarounds.h"
 
 /* Number of RX descriptors pushed at once. */
@@ -683,6 +684,15 @@
 	struct sk_buff *skb;
 	int lro = efx->net_dev->features & NETIF_F_LRO;
 
+	/* If we're in loopback test, then pass the packet directly to the
+	 * loopback layer, and free the rx_buf here
+	 */
+	if (unlikely(efx->loopback_selftest)) {
+		efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
+		efx_free_rx_buffer(efx, rx_buf);
+		goto done;
+	}
+
 	if (rx_buf->skb) {
 		prefetch(skb_shinfo(rx_buf->skb));
 
@@ -736,7 +746,6 @@
 	/* Update allocation strategy method */
 	channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
 
-	/* fall-thru */
 done:
 	efx->net_dev->last_rx = jiffies;
 }
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
new file mode 100644
index 0000000..cbda159
--- /dev/null
+++ b/drivers/net/sfc/selftest.c
@@ -0,0 +1,717 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/udp.h>
+#include <linux/rtnetlink.h>
+#include <asm/io.h>
+#include "net_driver.h"
+#include "ethtool.h"
+#include "efx.h"
+#include "falcon.h"
+#include "selftest.h"
+#include "boards.h"
+#include "workarounds.h"
+#include "mac.h"
+
+/*
+ * Loopback test packet structure
+ *
+ * The self-test should stress every RSS vector, and unfortunately
+ * Falcon only performs RSS on TCP/UDP packets.
+ */
+struct efx_loopback_payload {
+	struct ethhdr header;
+	struct iphdr ip;
+	struct udphdr udp;
+	__be16 iteration;
+	const char msg[64];
+} __attribute__ ((packed));
+
+/* Loopback test source MAC address */
+static const unsigned char payload_source[ETH_ALEN] = {
+	0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
+};
+
+static const char *payload_msg =
+	"Hello world! This is an Efx loopback test in progress!";
+
+/**
+ * efx_selftest_state - persistent state during a selftest
+ * @flush:		Drop all packets in efx_loopback_rx_packet
+ * @packet_count:	Number of packets being used in this test
+ * @skbs:		An array of skbs transmitted
+ * @rx_good:		RX good packet count
+ * @rx_bad:		RX bad packet count
+ * @payload:		Payload used in tests
+ */
+struct efx_selftest_state {
+	int flush;
+	int packet_count;
+	struct sk_buff **skbs;
+	atomic_t rx_good;
+	atomic_t rx_bad;
+	struct efx_loopback_payload payload;
+};
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************/
+
+/* Level of loopback testing
+ *
+ * The maximum packet burst length is 16**(n-1), i.e.
+ *
+ * - Level 0 : no packets
+ * - Level 1 : 1 packet
+ * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets)
+ * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets)
+ *
+ */
+static unsigned int loopback_test_level = 3;
+
+/**************************************************************************
+ *
+ * Interrupt and event queue testing
+ *
+ **************************************************************************/
+
+/* Test generation and receipt of interrupts */
+static int efx_test_interrupts(struct efx_nic *efx,
+			       struct efx_self_tests *tests)
+{
+	struct efx_channel *channel;
+
+	EFX_LOG(efx, "testing interrupts\n");
+	tests->interrupt = -1;
+
+	/* Reset interrupt flag */
+	efx->last_irq_cpu = -1;
+	smp_wmb();
+
+	/* ACK each interrupting event queue. Receiving an interrupt due to
+	 * traffic before a test event is raised is considered a pass */
+	efx_for_each_channel_with_interrupt(channel, efx) {
+		if (channel->work_pending)
+			efx_process_channel_now(channel);
+		if (efx->last_irq_cpu >= 0)
+			goto success;
+	}
+
+	falcon_generate_interrupt(efx);
+
+	/* Wait for arrival of test interrupt. */
+	EFX_LOG(efx, "waiting for test interrupt\n");
+	schedule_timeout_uninterruptible(HZ / 10);
+	if (efx->last_irq_cpu >= 0)
+		goto success;
+
+	EFX_ERR(efx, "timed out waiting for interrupt\n");
+	return -ETIMEDOUT;
+
+ success:
+	EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n",
+		efx->interrupt_mode, efx->last_irq_cpu);
+	tests->interrupt = 1;
+	return 0;
+}
+
+/* Test generation and receipt of non-interrupting events */
+static int efx_test_eventq(struct efx_channel *channel,
+			   struct efx_self_tests *tests)
+{
+	unsigned int magic;
+
+	/* Channel specific code, limited to 20 bits */
+	magic = (0x00010150 + channel->channel);
+	EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
+		channel->channel, magic);
+
+	tests->eventq_dma[channel->channel] = -1;
+	tests->eventq_int[channel->channel] = 1;	/* fake pass */
+	tests->eventq_poll[channel->channel] = 1;	/* fake pass */
+
+	/* Reset flag and zero magic word */
+	channel->efx->last_irq_cpu = -1;
+	channel->eventq_magic = 0;
+	smp_wmb();
+
+	falcon_generate_test_event(channel, magic);
+	udelay(1);
+
+	efx_process_channel_now(channel);
+	if (channel->eventq_magic != magic) {
+		EFX_ERR(channel->efx, "channel %d  failed to see test event\n",
+			channel->channel);
+		return -ETIMEDOUT;
+	} else {
+		tests->eventq_dma[channel->channel] = 1;
+	}
+
+	return 0;
+}
+
+/* Test generation and receipt of interrupting events */
+static int efx_test_eventq_irq(struct efx_channel *channel,
+			       struct efx_self_tests *tests)
+{
+	unsigned int magic, count;
+
+	/* Channel specific code, limited to 20 bits */
+	magic = (0x00010150 + channel->channel);
+	EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
+		channel->channel, magic);
+
+	tests->eventq_dma[channel->channel] = -1;
+	tests->eventq_int[channel->channel] = -1;
+	tests->eventq_poll[channel->channel] = -1;
+
+	/* Reset flag and zero magic word */
+	channel->efx->last_irq_cpu = -1;
+	channel->eventq_magic = 0;
+	smp_wmb();
+
+	falcon_generate_test_event(channel, magic);
+
+	/* Wait for arrival of interrupt */
+	count = 0;
+	do {
+		schedule_timeout_uninterruptible(HZ / 100);
+
+		if (channel->work_pending)
+			efx_process_channel_now(channel);
+
+		if (channel->eventq_magic == magic)
+			goto eventq_ok;
+	} while (++count < 2);
+
+	EFX_ERR(channel->efx, "channel %d timed out waiting for event queue\n",
+		channel->channel);
+
+	/* See if interrupt arrived */
+	if (channel->efx->last_irq_cpu >= 0) {
+		EFX_ERR(channel->efx, "channel %d saw interrupt on CPU%d "
+			"during event queue test\n", channel->channel,
+			raw_smp_processor_id());
+		tests->eventq_int[channel->channel] = 1;
+	}
+
+	/* Check to see if event was received even if interrupt wasn't */
+	efx_process_channel_now(channel);
+	if (channel->eventq_magic == magic) {
+		EFX_ERR(channel->efx, "channel %d event was generated, but "
+			"failed to trigger an interrupt\n", channel->channel);
+		tests->eventq_dma[channel->channel] = 1;
+	}
+
+	return -ETIMEDOUT;
+ eventq_ok:
+	EFX_LOG(channel->efx, "channel %d event queue passed\n",
+		channel->channel);
+	tests->eventq_dma[channel->channel] = 1;
+	tests->eventq_int[channel->channel] = 1;
+	tests->eventq_poll[channel->channel] = 1;
+	return 0;
+}
+
+/**************************************************************************
+ *
+ * PHY testing
+ *
+ **************************************************************************/
+
+/* Check PHY presence by reading the PHY ID registers */
+static int efx_test_phy(struct efx_nic *efx,
+			struct efx_self_tests *tests)
+{
+	u16 physid1, physid2;
+	struct mii_if_info *mii = &efx->mii;
+	struct net_device *net_dev = efx->net_dev;
+
+	if (efx->phy_type == PHY_TYPE_NONE)
+		return 0;
+
+	EFX_LOG(efx, "testing PHY presence\n");
+	tests->phy_ok = -1;
+
+	physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
+	physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
+
+	if ((physid1 != 0x0000) && (physid1 != 0xffff) &&
+	    (physid2 != 0x0000) && (physid2 != 0xffff)) {
+		EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n",
+			mii->phy_id, physid1, physid2);
+		tests->phy_ok = 1;
+		return 0;
+	}
+
+	EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id);
+	return -ENODEV;
+}
+
+/**************************************************************************
+ *
+ * Loopback testing
+ * NB Only one loopback test can be executing concurrently.
+ *
+ **************************************************************************/
+
+/* Loopback test RX callback
+ * This is called for each received packet during loopback testing.
+ */
+void efx_loopback_rx_packet(struct efx_nic *efx,
+			    const char *buf_ptr, int pkt_len)
+{
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_payload *received;
+	struct efx_loopback_payload *payload;
+
+	BUG_ON(!buf_ptr);
+
+	/* If we are just flushing, then drop the packet */
+	if ((state == NULL) || state->flush)
+		return;
+
+	payload = &state->payload;
+	
+	received = (struct efx_loopback_payload *)(char *) buf_ptr;
+	received->ip.saddr = payload->ip.saddr;
+	received->ip.check = payload->ip.check;
+	
+	/* Check that header exists */
+	if (pkt_len < sizeof(received->header)) {
+		EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
+			"test\n", pkt_len, LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Check that the ethernet header exists */
+	if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
+		EFX_ERR(efx, "saw non-loopback RX packet in %s loopback test\n",
+			LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Check packet length */
+	if (pkt_len != sizeof(*payload)) {
+		EFX_ERR(efx, "saw incorrect RX packet length %d (wanted %d) in "
+			"%s loopback test\n", pkt_len, (int)sizeof(*payload),
+			LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Check that IP header matches */
+	if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
+		EFX_ERR(efx, "saw corrupted IP header in %s loopback test\n",
+			LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Check that msg and padding matches */
+	if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
+		EFX_ERR(efx, "saw corrupted RX packet in %s loopback test\n",
+			LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Check that iteration matches */
+	if (received->iteration != payload->iteration) {
+		EFX_ERR(efx, "saw RX packet from iteration %d (wanted %d) in "
+			"%s loopback test\n", ntohs(received->iteration),
+			ntohs(payload->iteration), LOOPBACK_MODE(efx));
+		goto err;
+	}
+
+	/* Increase correct RX count */
+	EFX_TRACE(efx, "got loopback RX in %s loopback test\n",
+		  LOOPBACK_MODE(efx));
+
+	atomic_inc(&state->rx_good);
+	return;
+
+ err:
+#ifdef EFX_ENABLE_DEBUG
+	if (atomic_read(&state->rx_bad) == 0) {
+		EFX_ERR(efx, "received packet:\n");
+		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
+			       buf_ptr, pkt_len, 0);
+		EFX_ERR(efx, "expected packet:\n");
+		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
+			       &state->payload, sizeof(state->payload), 0);
+	}
+#endif
+	atomic_inc(&state->rx_bad);
+}
+
+/* Initialise an efx_selftest_state for a new iteration */
+static void efx_iterate_state(struct efx_nic *efx)
+{
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct net_device *net_dev = efx->net_dev;
+	struct efx_loopback_payload *payload = &state->payload;
+
+	/* Initialise the layerII header */
+	memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
+	memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
+	payload->header.h_proto = htons(ETH_P_IP);
+
+	/* saddr set later and used as incrementing count */
+	payload->ip.daddr = htonl(INADDR_LOOPBACK);
+	payload->ip.ihl = 5;
+	payload->ip.check = htons(0xdead);
+	payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr));
+	payload->ip.version = IPVERSION;
+	payload->ip.protocol = IPPROTO_UDP;
+
+	/* Initialise udp header */
+	payload->udp.source = 0;
+	payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) -
+				 sizeof(struct iphdr));
+	payload->udp.check = 0;	/* checksum ignored */
+
+	/* Fill out payload */
+	payload->iteration = htons(ntohs(payload->iteration) + 1);
+	memcpy(&payload->msg, payload_msg, sizeof(payload_msg));
+
+	/* Fill out remaining state members */
+	atomic_set(&state->rx_good, 0);
+	atomic_set(&state->rx_bad, 0);
+	smp_wmb();
+}
+
+static int efx_tx_loopback(struct efx_tx_queue *tx_queue)
+{
+	struct efx_nic *efx = tx_queue->efx;
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_loopback_payload *payload;
+	struct sk_buff *skb;
+	int i, rc;
+
+	/* Transmit N copies of buffer */
+	for (i = 0; i < state->packet_count; i++) {
+		/* Allocate an skb, holding an extra reference for 
+		 * transmit completion counting */
+		skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
+		if (!skb)
+			return -ENOMEM;
+		state->skbs[i] = skb;
+		skb_get(skb);
+
+		/* Copy the payload in, incrementing the source address to
+		 * exercise the rss vectors */
+		payload = ((struct efx_loopback_payload *)
+			   skb_put(skb, sizeof(state->payload)));
+		memcpy(payload, &state->payload, sizeof(state->payload));
+		payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2));
+
+		/* Ensure everything we've written is visible to the
+		 * interrupt handler. */
+		smp_wmb();
+
+		if (NET_DEV_REGISTERED(efx))
+			netif_tx_lock_bh(efx->net_dev);
+		rc = efx_xmit(efx, tx_queue, skb);
+		if (NET_DEV_REGISTERED(efx))
+			netif_tx_unlock_bh(efx->net_dev);
+
+		if (rc != NETDEV_TX_OK) {
+			EFX_ERR(efx, "TX queue %d could not transmit packet %d "
+				"of %d in %s loopback test\n", tx_queue->queue,
+				i + 1, state->packet_count, LOOPBACK_MODE(efx));
+
+			/* Defer cleaning up the other skbs for the caller */
+			kfree_skb(skb);
+			return -EPIPE;
+		}
+	}
+
+	return 0;
+}
+
+static int efx_rx_loopback(struct efx_tx_queue *tx_queue,
+			   struct efx_loopback_self_tests *lb_tests)
+{
+	struct efx_nic *efx = tx_queue->efx;
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct sk_buff *skb;
+	int tx_done = 0, rx_good, rx_bad;
+	int i, rc = 0;
+
+	if (NET_DEV_REGISTERED(efx))
+		netif_tx_lock_bh(efx->net_dev);
+
+	/* Count the number of tx completions, and decrement the refcnt. Any
+	 * skbs not already completed will be free'd when the queue is flushed */
+	for (i=0; i < state->packet_count; i++) {
+		skb = state->skbs[i];
+		if (skb && !skb_shared(skb))
+			++tx_done;
+		dev_kfree_skb_any(skb);
+	}
+
+	if (NET_DEV_REGISTERED(efx))
+		netif_tx_unlock_bh(efx->net_dev);
+
+	/* Check TX completion and received packet counts */
+	rx_good = atomic_read(&state->rx_good);
+	rx_bad = atomic_read(&state->rx_bad);
+	if (tx_done != state->packet_count) {
+		/* Don't free the skbs; they will be picked up on TX
+		 * overflow or channel teardown.
+		 */
+		EFX_ERR(efx, "TX queue %d saw only %d out of an expected %d "
+			"TX completion events in %s loopback test\n",
+			tx_queue->queue, tx_done, state->packet_count,
+			LOOPBACK_MODE(efx));
+		rc = -ETIMEDOUT;
+		/* Allow to fall through so we see the RX errors as well */
+	}
+
+	/* We may always be up to a flush away from our desired packet total */
+	if (rx_good != state->packet_count) {
+		EFX_LOG(efx, "TX queue %d saw only %d out of an expected %d "
+			"received packets in %s loopback test\n",
+			tx_queue->queue, rx_good, state->packet_count,
+			LOOPBACK_MODE(efx));
+		rc = -ETIMEDOUT;
+		/* Fall through */
+	}
+
+	/* Update loopback test structure */
+	lb_tests->tx_sent[tx_queue->queue] += state->packet_count;
+	lb_tests->tx_done[tx_queue->queue] += tx_done;
+	lb_tests->rx_good += rx_good;
+	lb_tests->rx_bad += rx_bad;
+
+	return rc;
+}
+
+static int
+efx_test_loopback(struct efx_tx_queue *tx_queue,
+		  struct efx_loopback_self_tests *lb_tests)
+{
+	struct efx_nic *efx = tx_queue->efx;
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct efx_channel *channel;
+	int i, rc = 0;
+
+	for (i = 0; i < loopback_test_level; i++) {
+		/* Determine how many packets to send */
+		state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
+		state->packet_count = min(1 << (i << 2), state->packet_count);
+		state->skbs = kzalloc(sizeof(state->skbs[0]) *
+				      state->packet_count, GFP_KERNEL);
+		state->flush = 0;
+
+		EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
+			"packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+			state->packet_count);
+
+		efx_iterate_state(efx);
+		rc = efx_tx_loopback(tx_queue);
+		
+		/* NAPI polling is not enabled, so process channels synchronously */
+		schedule_timeout_uninterruptible(HZ / 50);
+		efx_for_each_channel_with_interrupt(channel, efx) {
+			if (channel->work_pending)
+				efx_process_channel_now(channel);
+		}
+
+		rc |= efx_rx_loopback(tx_queue, lb_tests);
+		kfree(state->skbs);
+
+		if (rc) {
+			/* Wait a while to ensure there are no packets
+			 * floating around after a failure. */
+			schedule_timeout_uninterruptible(HZ / 10);
+			return rc;
+		}
+	}
+
+	EFX_LOG(efx, "TX queue %d passed %s loopback test with a burst length "
+		"of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+		state->packet_count);
+
+	return rc;
+}
+
+static int efx_test_loopbacks(struct efx_nic *efx,
+			      struct efx_self_tests *tests,
+			      unsigned int loopback_modes)
+{
+	struct efx_selftest_state *state = efx->loopback_selftest;
+	struct ethtool_cmd ecmd, ecmd_loopback;
+	struct efx_tx_queue *tx_queue;
+	enum efx_loopback_mode old_mode, mode;
+	int count, rc = 0, link_up;
+	
+	rc = efx_ethtool_get_settings(efx->net_dev, &ecmd);
+	if (rc) {
+		EFX_ERR(efx, "could not get GMII settings\n");
+		return rc;
+	}
+	old_mode = efx->loopback_mode;
+
+	/* Disable autonegotiation for the purposes of loopback */
+	memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback));
+	if (ecmd_loopback.autoneg == AUTONEG_ENABLE) {
+		ecmd_loopback.autoneg = AUTONEG_DISABLE;
+		ecmd_loopback.duplex = DUPLEX_FULL;
+		ecmd_loopback.speed = SPEED_10000;
+	}
+
+	rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback);
+	if (rc) {
+		EFX_ERR(efx, "could not disable autonegotiation\n");
+		goto out;
+	}
+	tests->loopback_speed = ecmd_loopback.speed;
+	tests->loopback_full_duplex = ecmd_loopback.duplex;
+
+	/* Test all supported loopback modes */
+	for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+		if (!(loopback_modes & (1 << mode)))
+			continue;
+
+		/* Move the port into the specified loopback mode. */
+		state->flush = 1;
+		efx->loopback_mode = mode;
+		efx_reconfigure_port(efx);
+
+		/* Wait for the PHY to signal the link is up */
+		count = 0;
+		do {
+			struct efx_channel *channel = &efx->channel[0];
+
+			falcon_check_xmac(efx);
+			schedule_timeout_uninterruptible(HZ / 10);
+			if (channel->work_pending)
+				efx_process_channel_now(channel);
+			/* Wait for PHY events to be processed */
+			flush_workqueue(efx->workqueue);
+			rmb();
+
+			/* efx->link_up can be 1 even if the XAUI link is down,
+			 * (bug5762). Usually, it's not worth bothering with the
+			 * difference, but for selftests, we need that extra
+			 * guarantee that the link is really, really, up.
+			 */
+			link_up = efx->link_up;
+			if (!falcon_xaui_link_ok(efx))
+				link_up = 0;
+
+		} while ((++count < 20) && !link_up);
+
+		/* The link should now be up. If it isn't, there is no point
+		 * in attempting a loopback test */
+		if (!link_up) {
+			EFX_ERR(efx, "loopback %s never came up\n",
+				LOOPBACK_MODE(efx));
+			rc = -EIO;
+			goto out;
+		}
+
+		EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
+			LOOPBACK_MODE(efx), count);
+
+		/* Test every TX queue */
+		efx_for_each_tx_queue(tx_queue, efx) {
+			rc |= efx_test_loopback(tx_queue,
+						&tests->loopback[mode]);
+			if (rc)
+				goto out;
+		}
+	}
+
+ out:
+	/* Take out of loopback and restore PHY settings */
+	state->flush = 1;
+	efx->loopback_mode = old_mode;
+	efx_ethtool_set_settings(efx->net_dev, &ecmd);
+
+	return rc;
+}
+
+/**************************************************************************
+ *
+ * Entry points
+ *
+ *************************************************************************/
+
+/* Online (i.e. non-disruptive) testing
+ * This checks interrupt generation, event delivery and PHY presence. */
+int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+	struct efx_channel *channel;
+	int rc = 0;
+
+	EFX_LOG(efx, "performing online self-tests\n");
+
+	rc |= efx_test_interrupts(efx, tests);
+	efx_for_each_channel(channel, efx) {
+		if (channel->has_interrupt)
+			rc |= efx_test_eventq_irq(channel, tests);
+		else
+			rc |= efx_test_eventq(channel, tests);
+	}
+	rc |= efx_test_phy(efx, tests);
+
+	if (rc)
+		EFX_ERR(efx, "failed online self-tests\n");
+
+	return rc;
+}
+
+/* Offline (i.e. disruptive) testing
+ * This checks MAC and PHY loopback on the specified port. */
+int efx_offline_test(struct efx_nic *efx,
+		     struct efx_self_tests *tests, unsigned int loopback_modes)
+{
+	struct efx_selftest_state *state;
+	int rc = 0;
+
+	EFX_LOG(efx, "performing offline self-tests\n");
+
+	/* Create a selftest_state structure to hold state for the test */
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Set the port loopback_selftest member. From this point on
+	 * all received packets will be dropped. Mark the state as
+	 * "flushing" so all inflight packets are dropped */
+	BUG_ON(efx->loopback_selftest);
+	state->flush = 1;
+	efx->loopback_selftest = (void *)state;
+
+	rc = efx_test_loopbacks(efx, tests, loopback_modes);
+
+	efx->loopback_selftest = NULL;
+	wmb();
+	kfree(state);
+
+ out:
+	if (rc)
+		EFX_ERR(efx, "failed offline self-tests\n");
+
+	return rc;
+}
+
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
new file mode 100644
index 0000000..f6999c2
--- /dev/null
+++ b/drivers/net/sfc/selftest.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_SELFTEST_H
+#define EFX_SELFTEST_H
+
+#include "net_driver.h"
+
+/*
+ * Self tests
+ */
+
+struct efx_loopback_self_tests {
+	int tx_sent[EFX_MAX_TX_QUEUES];
+	int tx_done[EFX_MAX_TX_QUEUES];
+	int rx_good;
+	int rx_bad;
+};
+
+/* Efx self test results
+ * For fields which are not counters, 1 indicates success and -1
+ * indicates failure.
+ */
+struct efx_self_tests {
+	int interrupt;
+	int eventq_dma[EFX_MAX_CHANNELS];
+	int eventq_int[EFX_MAX_CHANNELS];
+	int eventq_poll[EFX_MAX_CHANNELS];
+	int phy_ok;
+	int loopback_speed;
+	int loopback_full_duplex;
+	struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX];
+};
+
+extern void efx_loopback_rx_packet(struct efx_nic *efx,
+				   const char *buf_ptr, int pkt_len);
+extern int efx_online_test(struct efx_nic *efx,
+			   struct efx_self_tests *tests);
+extern int efx_offline_test(struct efx_nic *efx,
+			    struct efx_self_tests *tests,
+			    unsigned int loopback_modes);
+
+#endif /* EFX_SELFTEST_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index 11fa9fb..725d1a5 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -130,6 +130,15 @@
 	(void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
 }
 
+/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
+ * to the FLASH_CFG_1 input on the DSP.  We must keep it high at power-
+ * up to allow writing the flash (done through MDIO from userland).
+ */
+unsigned int sfe4001_phy_flash_cfg;
+module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444);
+MODULE_PARM_DESC(phy_flash_cfg,
+		 "Force PHY to enter flash configuration mode");
+
 /* This board uses an I2C expander to provider power to the PHY, which needs to
  * be turned on before the PHY can be used.
  * Context: Process context, rtnl lock held
@@ -203,6 +212,8 @@
 		out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
 			       (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
 			       (1 << P0_X_TRST_LBN));
+		if (sfe4001_phy_flash_cfg)
+			out |= 1 << P0_EN_3V3X_LBN;
 
 		rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
 		if (rc)
@@ -226,6 +237,9 @@
 		if (in & (1 << P1_AFE_PWD_LBN))
 			goto done;
 
+		/* DSP doesn't look powered in flash config mode */
+		if (sfe4001_phy_flash_cfg)
+			goto done;
 	} while (++count < 20);
 
 	EFX_INFO(efx, "timed out waiting for power\n");
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index a2e9f79..b1cd6de 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -24,6 +24,11 @@
 				 MDIO_MMDREG_DEVS0_PCS    | \
 				 MDIO_MMDREG_DEVS0_PHYXS)
 
+#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
+			     (1 << LOOPBACK_PCS) |	\
+			     (1 << LOOPBACK_PMAPMD) |	\
+			     (1 << LOOPBACK_NETWORK))
+
 /* We complain if we fail to see the link partner as 10G capable this many
  * times in a row (must be > 1 as sampling the autoneg. registers is racy)
  */
@@ -72,6 +77,10 @@
 #define PMA_PMD_BIST_RXD_LBN	(1)
 #define PMA_PMD_BIST_AFE_LBN	(0)
 
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
 #define BIST_MAX_DELAY	(1000)
 #define BIST_POLL_DELAY	(10)
 
@@ -86,6 +95,11 @@
 #define	PCS_TEST_SELECT_REG 0xd807	/* PRM 10.5.8 */
 #define	CLK312_EN_LBN 3
 
+/* PHYXS registers */
+#define PHYXS_TEST1         (49162)
+#define LOOPBACK_NEAR_LBN   (8)
+#define LOOPBACK_NEAR_WIDTH (1)
+
 /* Boot status register */
 #define PCS_BOOT_STATUS_REG	(0xd000)
 #define PCS_BOOT_FATAL_ERR_LBN	(0)
@@ -106,7 +120,9 @@
 
 struct tenxpress_phy_data {
 	enum tenxpress_state state;
+	enum efx_loopback_mode loopback_mode;
 	atomic_t bad_crc_count;
+	int tx_disabled;
 	int bad_lp_tries;
 };
 
@@ -199,10 +215,12 @@
 
 	tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
 
-	rc = mdio_clause45_wait_reset_mmds(efx,
-					   TENXPRESS_REQUIRED_DEVS);
-	if (rc < 0)
-		goto fail;
+	if (!sfe4001_phy_flash_cfg) {
+		rc = mdio_clause45_wait_reset_mmds(efx,
+						   TENXPRESS_REQUIRED_DEVS);
+		if (rc < 0)
+			goto fail;
+	}
 
 	rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
 	if (rc < 0)
@@ -225,6 +243,35 @@
 	return rc;
 }
 
+static int tenxpress_special_reset(struct efx_nic *efx)
+{
+	int rc, reg;
+
+	EFX_TRACE(efx, "%s\n", __func__);
+
+	/* Initiate reset */
+	reg = mdio_clause45_read(efx, efx->mii.phy_id,
+				 MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG);
+	reg |= (1 << PMA_PMD_EXT_SSR_LBN);
+	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+			    PMA_PMD_EXT_CTRL_REG, reg);
+
+	msleep(200);
+
+	/* Wait for the blocks to come out of reset */
+	rc = mdio_clause45_wait_reset_mmds(efx,
+					   TENXPRESS_REQUIRED_DEVS);
+	if (rc < 0)
+		return rc;
+
+	/* Try and reconfigure the device */
+	rc = tenxpress_init(efx);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
 static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
 {
 	struct tenxpress_phy_data *pd = efx->phy_data;
@@ -299,11 +346,46 @@
 	return ok;
 }
 
+static void tenxpress_phyxs_loopback(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+	int ctrl1, ctrl2;
+
+	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
+					   PHYXS_TEST1);
+	if (efx->loopback_mode == LOOPBACK_PHYXS)
+		ctrl2 |= (1 << LOOPBACK_NEAR_LBN);
+	else
+		ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN);
+	if (ctrl1 != ctrl2)
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
+				    PHYXS_TEST1, ctrl2);
+}
+
 static void tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
+	struct tenxpress_phy_data *phy_data = efx->phy_data;
+	int loop_change = LOOPBACK_OUT_OF(phy_data, efx,
+					  TENXPRESS_LOOPBACKS);
+
 	if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
 		return;
 
+	/* When coming out of transmit disable, coming out of low power
+	 * mode, or moving out of any PHY internal loopback mode,
+	 * perform a special software reset */
+	if ((phy_data->tx_disabled && !efx->tx_disabled) ||
+	    loop_change) {
+		(void) tenxpress_special_reset(efx);
+		falcon_reset_xaui(efx);
+	}
+
+	mdio_clause45_transmit_disable(efx);
+	mdio_clause45_phy_reconfigure(efx);
+	tenxpress_phyxs_loopback(efx);
+
+	phy_data->tx_disabled = efx->tx_disabled;
+	phy_data->loopback_mode = efx->loopback_mode;
 	efx->link_up = tenxpress_link_ok(efx, 0);
 	efx->link_options = GM_LPA_10000FULL;
 }
@@ -431,4 +513,5 @@
 	.clear_interrupt  = tenxpress_phy_clear_interrupt,
 	.reset_xaui       = tenxpress_reset_xaui,
 	.mmds             = TENXPRESS_REQUIRED_DEVS,
+	.loopbacks        = TENXPRESS_LOOPBACKS,
 };
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index fbb866b..9b436f5 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -82,6 +82,46 @@
 	}
 }
 
+/**
+ * struct efx_tso_header - a DMA mapped buffer for packet headers
+ * @next: Linked list of free ones.
+ *	The list is protected by the TX queue lock.
+ * @dma_unmap_len: Length to unmap for an oversize buffer, or 0.
+ * @dma_addr: The DMA address of the header below.
+ *
+ * This controls the memory used for a TSO header.  Use TSOH_DATA()
+ * to find the packet header data.  Use TSOH_SIZE() to calculate the
+ * total size required for a given packet header length.  TSO headers
+ * in the free list are exactly %TSOH_STD_SIZE bytes in size.
+ */
+struct efx_tso_header {
+	union {
+		struct efx_tso_header *next;
+		size_t unmap_len;
+	};
+	dma_addr_t dma_addr;
+};
+
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+			       const struct sk_buff *skb);
+static void efx_fini_tso(struct efx_tx_queue *tx_queue);
+static void efx_tsoh_heap_free(struct efx_tx_queue *tx_queue,
+			       struct efx_tso_header *tsoh);
+
+static inline void efx_tsoh_free(struct efx_tx_queue *tx_queue,
+				 struct efx_tx_buffer *buffer)
+{
+	if (buffer->tsoh) {
+		if (likely(!buffer->tsoh->unmap_len)) {
+			buffer->tsoh->next = tx_queue->tso_headers_free;
+			tx_queue->tso_headers_free = buffer->tsoh;
+		} else {
+			efx_tsoh_heap_free(tx_queue, buffer->tsoh);
+		}
+		buffer->tsoh = NULL;
+	}
+}
+
 
 /*
  * Add a socket buffer to a TX queue
@@ -114,6 +154,9 @@
 
 	EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
 
+	if (skb_shinfo((struct sk_buff *)skb)->gso_size)
+		return efx_enqueue_skb_tso(tx_queue, skb);
+
 	/* Get size of the initial fragment */
 	len = skb_headlen(skb);
 
@@ -166,6 +209,8 @@
 			insert_ptr = (tx_queue->insert_count &
 				      efx->type->txd_ring_mask);
 			buffer = &tx_queue->buffer[insert_ptr];
+			efx_tsoh_free(tx_queue, buffer);
+			EFX_BUG_ON_PARANOID(buffer->tsoh);
 			EFX_BUG_ON_PARANOID(buffer->skb);
 			EFX_BUG_ON_PARANOID(buffer->len);
 			EFX_BUG_ON_PARANOID(buffer->continuation != 1);
@@ -432,6 +477,9 @@
 
 	efx_release_tx_buffers(tx_queue);
 
+	/* Free up TSO header cache */
+	efx_fini_tso(tx_queue);
+
 	/* Release queue's stop on port, if any */
 	if (tx_queue->stopped) {
 		tx_queue->stopped = 0;
@@ -450,3 +498,619 @@
 }
 
 
+/* Efx TCP segmentation acceleration.
+ *
+ * Why?  Because by doing it here in the driver we can go significantly
+ * faster than the GSO.
+ *
+ * Requires TX checksum offload support.
+ */
+
+/* Number of bytes inserted at the start of a TSO header buffer,
+ * similar to NET_IP_ALIGN.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define TSOH_OFFSET	0
+#else
+#define TSOH_OFFSET	NET_IP_ALIGN
+#endif
+
+#define TSOH_BUFFER(tsoh)	((u8 *)(tsoh + 1) + TSOH_OFFSET)
+
+/* Total size of struct efx_tso_header, buffer and padding */
+#define TSOH_SIZE(hdr_len)					\
+	(sizeof(struct efx_tso_header) + TSOH_OFFSET + hdr_len)
+
+/* Size of blocks on free list.  Larger blocks must be allocated from
+ * the heap.
+ */
+#define TSOH_STD_SIZE		128
+
+#define PTR_DIFF(p1, p2)  ((u8 *)(p1) - (u8 *)(p2))
+#define ETH_HDR_LEN(skb)  (skb_network_header(skb) - (skb)->data)
+#define SKB_TCP_OFF(skb)  PTR_DIFF(tcp_hdr(skb), (skb)->data)
+#define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data)
+
+/**
+ * struct tso_state - TSO state for an SKB
+ * @remaining_len: Bytes of data we've yet to segment
+ * @seqnum: Current sequence number
+ * @packet_space: Remaining space in current packet
+ * @ifc: Input fragment cursor.
+ *	Where we are in the current fragment of the incoming SKB.  These
+ *	values get updated in place when we split a fragment over
+ *	multiple packets.
+ * @p: Parameters.
+ *	These values are set once at the start of the TSO send and do
+ *	not get changed as the routine progresses.
+ *
+ * The state used during segmentation.  It is put into this data structure
+ * just to make it easy to pass into inline functions.
+ */
+struct tso_state {
+	unsigned remaining_len;
+	unsigned seqnum;
+	unsigned packet_space;
+
+	struct {
+		/* DMA address of current position */
+		dma_addr_t dma_addr;
+		/* Remaining length */
+		unsigned int len;
+		/* DMA address and length of the whole fragment */
+		unsigned int unmap_len;
+		dma_addr_t unmap_addr;
+		struct page *page;
+		unsigned page_off;
+	} ifc;
+
+	struct {
+		/* The number of bytes of header */
+		unsigned int header_length;
+
+		/* The number of bytes to put in each outgoing segment. */
+		int full_packet_size;
+
+		/* Current IPv4 ID, host endian. */
+		unsigned ipv4_id;
+	} p;
+};
+
+
+/*
+ * Verify that our various assumptions about sk_buffs and the conditions
+ * under which TSO will be attempted hold true.
+ */
+static inline void efx_tso_check_safe(const struct sk_buff *skb)
+{
+	EFX_BUG_ON_PARANOID(skb->protocol != htons(ETH_P_IP));
+	EFX_BUG_ON_PARANOID(((struct ethhdr *)skb->data)->h_proto !=
+			    skb->protocol);
+	EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP);
+	EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data)
+			     + (tcp_hdr(skb)->doff << 2u)) >
+			    skb_headlen(skb));
+}
+
+
+/*
+ * Allocate a page worth of efx_tso_header structures, and string them
+ * into the tx_queue->tso_headers_free linked list. Return 0 or -ENOMEM.
+ */
+static int efx_tsoh_block_alloc(struct efx_tx_queue *tx_queue)
+{
+
+	struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+	struct efx_tso_header *tsoh;
+	dma_addr_t dma_addr;
+	u8 *base_kva, *kva;
+
+	base_kva = pci_alloc_consistent(pci_dev, PAGE_SIZE, &dma_addr);
+	if (base_kva == NULL) {
+		EFX_ERR(tx_queue->efx, "Unable to allocate page for TSO"
+			" headers\n");
+		return -ENOMEM;
+	}
+
+	/* pci_alloc_consistent() allocates pages. */
+	EFX_BUG_ON_PARANOID(dma_addr & (PAGE_SIZE - 1u));
+
+	for (kva = base_kva; kva < base_kva + PAGE_SIZE; kva += TSOH_STD_SIZE) {
+		tsoh = (struct efx_tso_header *)kva;
+		tsoh->dma_addr = dma_addr + (TSOH_BUFFER(tsoh) - base_kva);
+		tsoh->next = tx_queue->tso_headers_free;
+		tx_queue->tso_headers_free = tsoh;
+	}
+
+	return 0;
+}
+
+
+/* Free up a TSO header, and all others in the same page. */
+static void efx_tsoh_block_free(struct efx_tx_queue *tx_queue,
+				struct efx_tso_header *tsoh,
+				struct pci_dev *pci_dev)
+{
+	struct efx_tso_header **p;
+	unsigned long base_kva;
+	dma_addr_t base_dma;
+
+	base_kva = (unsigned long)tsoh & PAGE_MASK;
+	base_dma = tsoh->dma_addr & PAGE_MASK;
+
+	p = &tx_queue->tso_headers_free;
+	while (*p != NULL)
+		if (((unsigned long)*p & PAGE_MASK) == base_kva)
+			*p = (*p)->next;
+		else
+			p = &(*p)->next;
+
+	pci_free_consistent(pci_dev, PAGE_SIZE, (void *)base_kva, base_dma);
+}
+
+static struct efx_tso_header *
+efx_tsoh_heap_alloc(struct efx_tx_queue *tx_queue, size_t header_len)
+{
+	struct efx_tso_header *tsoh;
+
+	tsoh = kmalloc(TSOH_SIZE(header_len), GFP_ATOMIC | GFP_DMA);
+	if (unlikely(!tsoh))
+		return NULL;
+
+	tsoh->dma_addr = pci_map_single(tx_queue->efx->pci_dev,
+					TSOH_BUFFER(tsoh), header_len,
+					PCI_DMA_TODEVICE);
+	if (unlikely(pci_dma_mapping_error(tsoh->dma_addr))) {
+		kfree(tsoh);
+		return NULL;
+	}
+
+	tsoh->unmap_len = header_len;
+	return tsoh;
+}
+
+static void
+efx_tsoh_heap_free(struct efx_tx_queue *tx_queue, struct efx_tso_header *tsoh)
+{
+	pci_unmap_single(tx_queue->efx->pci_dev,
+			 tsoh->dma_addr, tsoh->unmap_len,
+			 PCI_DMA_TODEVICE);
+	kfree(tsoh);
+}
+
+/**
+ * efx_tx_queue_insert - push descriptors onto the TX queue
+ * @tx_queue:		Efx TX queue
+ * @dma_addr:		DMA address of fragment
+ * @len:		Length of fragment
+ * @skb:		Only non-null for end of last segment
+ * @end_of_packet:	True if last fragment in a packet
+ * @unmap_addr:		DMA address of fragment for unmapping
+ * @unmap_len:		Only set this in last segment of a fragment
+ *
+ * Push descriptors onto the TX queue.  Return 0 on success or 1 if
+ * @tx_queue full.
+ */
+static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
+			       dma_addr_t dma_addr, unsigned len,
+			       const struct sk_buff *skb, int end_of_packet,
+			       dma_addr_t unmap_addr, unsigned unmap_len)
+{
+	struct efx_tx_buffer *buffer;
+	struct efx_nic *efx = tx_queue->efx;
+	unsigned dma_len, fill_level, insert_ptr, misalign;
+	int q_space;
+
+	EFX_BUG_ON_PARANOID(len <= 0);
+
+	fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+	/* -1 as there is no way to represent all descriptors used */
+	q_space = efx->type->txd_ring_mask - 1 - fill_level;
+
+	while (1) {
+		if (unlikely(q_space-- <= 0)) {
+			/* It might be that completions have happened
+			 * since the xmit path last checked.  Update
+			 * the xmit path's copy of read_count.
+			 */
+			++tx_queue->stopped;
+			/* This memory barrier protects the change of
+			 * stopped from the access of read_count. */
+			smp_mb();
+			tx_queue->old_read_count =
+				*(volatile unsigned *)&tx_queue->read_count;
+			fill_level = (tx_queue->insert_count
+				      - tx_queue->old_read_count);
+			q_space = efx->type->txd_ring_mask - 1 - fill_level;
+			if (unlikely(q_space-- <= 0))
+				return 1;
+			smp_mb();
+			--tx_queue->stopped;
+		}
+
+		insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+		buffer = &tx_queue->buffer[insert_ptr];
+		++tx_queue->insert_count;
+
+		EFX_BUG_ON_PARANOID(tx_queue->insert_count -
+				    tx_queue->read_count >
+				    efx->type->txd_ring_mask);
+
+		efx_tsoh_free(tx_queue, buffer);
+		EFX_BUG_ON_PARANOID(buffer->len);
+		EFX_BUG_ON_PARANOID(buffer->unmap_len);
+		EFX_BUG_ON_PARANOID(buffer->skb);
+		EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+		EFX_BUG_ON_PARANOID(buffer->tsoh);
+
+		buffer->dma_addr = dma_addr;
+
+		/* Ensure we do not cross a boundary unsupported by H/W */
+		dma_len = (~dma_addr & efx->type->tx_dma_mask) + 1;
+
+		misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
+		if (misalign && dma_len + misalign > 512)
+			dma_len = 512 - misalign;
+
+		/* If there is enough space to send then do so */
+		if (dma_len >= len)
+			break;
+
+		buffer->len = dma_len; /* Don't set the other members */
+		dma_addr += dma_len;
+		len -= dma_len;
+	}
+
+	EFX_BUG_ON_PARANOID(!len);
+	buffer->len = len;
+	buffer->skb = skb;
+	buffer->continuation = !end_of_packet;
+	buffer->unmap_addr = unmap_addr;
+	buffer->unmap_len = unmap_len;
+	return 0;
+}
+
+
+/*
+ * Put a TSO header into the TX queue.
+ *
+ * This is special-cased because we know that it is small enough to fit in
+ * a single fragment, and we know it doesn't cross a page boundary.  It
+ * also allows us to not worry about end-of-packet etc.
+ */
+static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue,
+				      struct efx_tso_header *tsoh, unsigned len)
+{
+	struct efx_tx_buffer *buffer;
+
+	buffer = &tx_queue->buffer[tx_queue->insert_count &
+				   tx_queue->efx->type->txd_ring_mask];
+	efx_tsoh_free(tx_queue, buffer);
+	EFX_BUG_ON_PARANOID(buffer->len);
+	EFX_BUG_ON_PARANOID(buffer->unmap_len);
+	EFX_BUG_ON_PARANOID(buffer->skb);
+	EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+	EFX_BUG_ON_PARANOID(buffer->tsoh);
+	buffer->len = len;
+	buffer->dma_addr = tsoh->dma_addr;
+	buffer->tsoh = tsoh;
+
+	++tx_queue->insert_count;
+}
+
+
+/* Remove descriptors put into a tx_queue. */
+static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
+{
+	struct efx_tx_buffer *buffer;
+
+	/* Work backwards until we hit the original insert pointer value */
+	while (tx_queue->insert_count != tx_queue->write_count) {
+		--tx_queue->insert_count;
+		buffer = &tx_queue->buffer[tx_queue->insert_count &
+					   tx_queue->efx->type->txd_ring_mask];
+		efx_tsoh_free(tx_queue, buffer);
+		EFX_BUG_ON_PARANOID(buffer->skb);
+		buffer->len = 0;
+		buffer->continuation = 1;
+		if (buffer->unmap_len) {
+			pci_unmap_page(tx_queue->efx->pci_dev,
+				       buffer->unmap_addr,
+				       buffer->unmap_len, PCI_DMA_TODEVICE);
+			buffer->unmap_len = 0;
+		}
+	}
+}
+
+
+/* Parse the SKB header and initialise state. */
+static inline void tso_start(struct tso_state *st, const struct sk_buff *skb)
+{
+	/* All ethernet/IP/TCP headers combined size is TCP header size
+	 * plus offset of TCP header relative to start of packet.
+	 */
+	st->p.header_length = ((tcp_hdr(skb)->doff << 2u)
+			       + PTR_DIFF(tcp_hdr(skb), skb->data));
+	st->p.full_packet_size = (st->p.header_length
+				  + skb_shinfo(skb)->gso_size);
+
+	st->p.ipv4_id = ntohs(ip_hdr(skb)->id);
+	st->seqnum = ntohl(tcp_hdr(skb)->seq);
+
+	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg);
+	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn);
+	EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst);
+
+	st->packet_space = st->p.full_packet_size;
+	st->remaining_len = skb->len - st->p.header_length;
+}
+
+
+/**
+ * tso_get_fragment - record fragment details and map for DMA
+ * @st:			TSO state
+ * @efx:		Efx NIC
+ * @data:		Pointer to fragment data
+ * @len:		Length of fragment
+ *
+ * Record fragment details and map for DMA.  Return 0 on success, or
+ * -%ENOMEM if DMA mapping fails.
+ */
+static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
+				   int len, struct page *page, int page_off)
+{
+
+	st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off,
+					  len, PCI_DMA_TODEVICE);
+	if (likely(!pci_dma_mapping_error(st->ifc.unmap_addr))) {
+		st->ifc.unmap_len = len;
+		st->ifc.len = len;
+		st->ifc.dma_addr = st->ifc.unmap_addr;
+		st->ifc.page = page;
+		st->ifc.page_off = page_off;
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+
+/**
+ * tso_fill_packet_with_fragment - form descriptors for the current fragment
+ * @tx_queue:		Efx TX queue
+ * @skb:		Socket buffer
+ * @st:			TSO state
+ *
+ * Form descriptors for the current fragment, until we reach the end
+ * of fragment or end-of-packet.  Return 0 on success, 1 if not enough
+ * space in @tx_queue.
+ */
+static inline int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
+						const struct sk_buff *skb,
+						struct tso_state *st)
+{
+
+	int n, end_of_packet, rc;
+
+	if (st->ifc.len == 0)
+		return 0;
+	if (st->packet_space == 0)
+		return 0;
+
+	EFX_BUG_ON_PARANOID(st->ifc.len <= 0);
+	EFX_BUG_ON_PARANOID(st->packet_space <= 0);
+
+	n = min(st->ifc.len, st->packet_space);
+
+	st->packet_space -= n;
+	st->remaining_len -= n;
+	st->ifc.len -= n;
+	st->ifc.page_off += n;
+	end_of_packet = st->remaining_len == 0 || st->packet_space == 0;
+
+	rc = efx_tx_queue_insert(tx_queue, st->ifc.dma_addr, n,
+				 st->remaining_len ? NULL : skb,
+				 end_of_packet, st->ifc.unmap_addr,
+				 st->ifc.len ? 0 : st->ifc.unmap_len);
+
+	st->ifc.dma_addr += n;
+
+	return rc;
+}
+
+
+/**
+ * tso_start_new_packet - generate a new header and prepare for the new packet
+ * @tx_queue:		Efx TX queue
+ * @skb:		Socket buffer
+ * @st:			TSO state
+ *
+ * Generate a new header and prepare for the new packet.  Return 0 on
+ * success, or -1 if failed to alloc header.
+ */
+static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue,
+				       const struct sk_buff *skb,
+				       struct tso_state *st)
+{
+	struct efx_tso_header *tsoh;
+	struct iphdr *tsoh_iph;
+	struct tcphdr *tsoh_th;
+	unsigned ip_length;
+	u8 *header;
+
+	/* Allocate a DMA-mapped header buffer. */
+	if (likely(TSOH_SIZE(st->p.header_length) <= TSOH_STD_SIZE)) {
+		if (tx_queue->tso_headers_free == NULL)
+			if (efx_tsoh_block_alloc(tx_queue))
+				return -1;
+		EFX_BUG_ON_PARANOID(!tx_queue->tso_headers_free);
+		tsoh = tx_queue->tso_headers_free;
+		tx_queue->tso_headers_free = tsoh->next;
+		tsoh->unmap_len = 0;
+	} else {
+		tx_queue->tso_long_headers++;
+		tsoh = efx_tsoh_heap_alloc(tx_queue, st->p.header_length);
+		if (unlikely(!tsoh))
+			return -1;
+	}
+
+	header = TSOH_BUFFER(tsoh);
+	tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb));
+	tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb));
+
+	/* Copy and update the headers. */
+	memcpy(header, skb->data, st->p.header_length);
+
+	tsoh_th->seq = htonl(st->seqnum);
+	st->seqnum += skb_shinfo(skb)->gso_size;
+	if (st->remaining_len > skb_shinfo(skb)->gso_size) {
+		/* This packet will not finish the TSO burst. */
+		ip_length = st->p.full_packet_size - ETH_HDR_LEN(skb);
+		tsoh_th->fin = 0;
+		tsoh_th->psh = 0;
+	} else {
+		/* This packet will be the last in the TSO burst. */
+		ip_length = (st->p.header_length - ETH_HDR_LEN(skb)
+			     + st->remaining_len);
+		tsoh_th->fin = tcp_hdr(skb)->fin;
+		tsoh_th->psh = tcp_hdr(skb)->psh;
+	}
+	tsoh_iph->tot_len = htons(ip_length);
+
+	/* Linux leaves suitable gaps in the IP ID space for us to fill. */
+	tsoh_iph->id = htons(st->p.ipv4_id);
+	st->p.ipv4_id++;
+
+	st->packet_space = skb_shinfo(skb)->gso_size;
+	++tx_queue->tso_packets;
+
+	/* Form a descriptor for this header. */
+	efx_tso_put_header(tx_queue, tsoh, st->p.header_length);
+
+	return 0;
+}
+
+
+/**
+ * efx_enqueue_skb_tso - segment and transmit a TSO socket buffer
+ * @tx_queue:		Efx TX queue
+ * @skb:		Socket buffer
+ *
+ * Context: You must hold netif_tx_lock() to call this function.
+ *
+ * Add socket buffer @skb to @tx_queue, doing TSO or return != 0 if
+ * @skb was not enqueued.  In all cases @skb is consumed.  Return
+ * %NETDEV_TX_OK or %NETDEV_TX_BUSY.
+ */
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+			       const struct sk_buff *skb)
+{
+	int frag_i, rc, rc2 = NETDEV_TX_OK;
+	struct tso_state state;
+	skb_frag_t *f;
+
+	/* Verify TSO is safe - these checks should never fail. */
+	efx_tso_check_safe(skb);
+
+	EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+	tso_start(&state, skb);
+
+	/* Assume that skb header area contains exactly the headers, and
+	 * all payload is in the frag list.
+	 */
+	if (skb_headlen(skb) == state.p.header_length) {
+		/* Grab the first payload fragment. */
+		EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1);
+		frag_i = 0;
+		f = &skb_shinfo(skb)->frags[frag_i];
+		rc = tso_get_fragment(&state, tx_queue->efx,
+				      f->size, f->page, f->page_offset);
+		if (rc)
+			goto mem_err;
+	} else {
+		/* It may look like this code fragment assumes that the
+		 * skb->data portion does not cross a page boundary, but
+		 * that is not the case.  It is guaranteed to be direct
+		 * mapped memory, and therefore is physically contiguous,
+		 * and so DMA will work fine.  kmap_atomic() on this region
+		 * will just return the direct mapping, so that will work
+		 * too.
+		 */
+		int page_off = (unsigned long)skb->data & (PAGE_SIZE - 1);
+		int hl = state.p.header_length;
+		rc = tso_get_fragment(&state, tx_queue->efx,
+				      skb_headlen(skb) - hl,
+				      virt_to_page(skb->data), page_off + hl);
+		if (rc)
+			goto mem_err;
+		frag_i = -1;
+	}
+
+	if (tso_start_new_packet(tx_queue, skb, &state) < 0)
+		goto mem_err;
+
+	while (1) {
+		rc = tso_fill_packet_with_fragment(tx_queue, skb, &state);
+		if (unlikely(rc))
+			goto stop;
+
+		/* Move onto the next fragment? */
+		if (state.ifc.len == 0) {
+			if (++frag_i >= skb_shinfo(skb)->nr_frags)
+				/* End of payload reached. */
+				break;
+			f = &skb_shinfo(skb)->frags[frag_i];
+			rc = tso_get_fragment(&state, tx_queue->efx,
+					      f->size, f->page, f->page_offset);
+			if (rc)
+				goto mem_err;
+		}
+
+		/* Start at new packet? */
+		if (state.packet_space == 0 &&
+		    tso_start_new_packet(tx_queue, skb, &state) < 0)
+			goto mem_err;
+	}
+
+	/* Pass off to hardware */
+	falcon_push_buffers(tx_queue);
+
+	tx_queue->tso_bursts++;
+	return NETDEV_TX_OK;
+
+ mem_err:
+	EFX_ERR(tx_queue->efx, "Out of memory for TSO headers, or PCI mapping"
+		" error\n");
+	dev_kfree_skb_any((struct sk_buff *)skb);
+	goto unwind;
+
+ stop:
+	rc2 = NETDEV_TX_BUSY;
+
+	/* Stop the queue if it wasn't stopped before. */
+	if (tx_queue->stopped == 1)
+		efx_stop_queue(tx_queue->efx);
+
+ unwind:
+	efx_enqueue_unwind(tx_queue);
+	return rc2;
+}
+
+
+/*
+ * Free up all TSO datastructures associated with tx_queue. This
+ * routine should be called only once the tx_queue is both empty and
+ * will no longer be used.
+ */
+static void efx_fini_tso(struct efx_tx_queue *tx_queue)
+{
+	unsigned i;
+
+	if (tx_queue->buffer)
+		for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i)
+			efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
+
+	while (tx_queue->tso_headers_free != NULL)
+		efx_tsoh_block_free(tx_queue, tx_queue->tso_headers_free,
+				    tx_queue->efx->pci_dev);
+}
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
index 66dd5bf..3b9f9dd 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/xfp_phy.c
@@ -24,6 +24,10 @@
 			   MDIO_MMDREG_DEVS0_PMAPMD |	\
 			   MDIO_MMDREG_DEVS0_PHYXS)
 
+#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) |		\
+		       (1 << LOOPBACK_PMAPMD) |		\
+		       (1 << LOOPBACK_NETWORK))
+
 /****************************************************************************/
 /* Quake-specific MDIO registers */
 #define MDIO_QUAKE_LED0_REG	(0xD006)
@@ -35,6 +39,10 @@
 			    mode);
 }
 
+struct xfp_phy_data {
+	int tx_disabled;
+};
+
 #define XFP_MAX_RESET_TIME 500
 #define XFP_RESET_WAIT 10
 
@@ -72,18 +80,31 @@
 
 static int xfp_phy_init(struct efx_nic *efx)
 {
+	struct xfp_phy_data *phy_data;
 	u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
 	int rc;
 
+	phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
+	efx->phy_data = (void *) phy_data;
+
 	EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
 		 " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
 		 MDIO_ID_REV(devid));
 
+	phy_data->tx_disabled = efx->tx_disabled;
+
 	rc = xfp_reset_phy(efx);
 
 	EFX_INFO(efx, "XFP: PHY init %s.\n",
 		 rc ? "failed" : "successful");
+	if (rc < 0)
+		goto fail;
 
+	return 0;
+
+ fail:
+	kfree(efx->phy_data);
+	efx->phy_data = NULL;
 	return rc;
 }
 
@@ -110,6 +131,16 @@
 
 static void xfp_phy_reconfigure(struct efx_nic *efx)
 {
+	struct xfp_phy_data *phy_data = efx->phy_data;
+
+	/* Reset the PHY when moving from tx off to tx on */
+	if (phy_data->tx_disabled && !efx->tx_disabled)
+		xfp_reset_phy(efx);
+
+	mdio_clause45_transmit_disable(efx);
+	mdio_clause45_phy_reconfigure(efx);
+
+	phy_data->tx_disabled = efx->tx_disabled;
 	efx->link_up = xfp_link_ok(efx);
 	efx->link_options = GM_LPA_10000FULL;
 }
@@ -119,6 +150,10 @@
 {
 	/* Clobber the LED if it was blinking */
 	efx->board_info.blink(efx, 0);
+
+	/* Free the context block */
+	kfree(efx->phy_data);
+	efx->phy_data = NULL;
 }
 
 struct efx_phy_operations falcon_xfp_phy_ops = {
@@ -129,4 +164,5 @@
 	.clear_interrupt = xfp_phy_clear_interrupt,
 	.reset_xaui      = efx_port_dummy_op_void,
 	.mmds            = XFP_REQUIRED_DEVS,
+	.loopbacks       = XFP_LOOPBACKS,
 };
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 7bb3ba9..c0a5eea 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1966,13 +1966,13 @@
 struct tx_ring_info {
 	struct sk_buff	*skb;
 	DECLARE_PCI_UNMAP_ADDR(mapaddr);
-	DECLARE_PCI_UNMAP_ADDR(maplen);
+	DECLARE_PCI_UNMAP_LEN(maplen);
 };
 
 struct rx_ring_info {
 	struct sk_buff	*skb;
 	dma_addr_t	data_addr;
-	DECLARE_PCI_UNMAP_ADDR(data_size);
+	DECLARE_PCI_UNMAP_LEN(data_size);
 	dma_addr_t	frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
 };
 
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 8005dd1..d5140ae 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -150,11 +150,9 @@
 
 config HDLC_PPP
 	tristate "Synchronous Point-to-Point Protocol (PPP) support"
-	depends on HDLC && BROKEN
+	depends on HDLC
 	help
 	  Generic HDLC driver supporting PPP over WAN connections.
-	  This module is currently broken and will cause a kernel panic
-	  when a device configured in PPP mode is activated.
 
 	  It will be replaced by new PPP implementation in Linux 2.6.26.
 
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 45ddfc9..b0fce13 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -629,7 +629,7 @@
 	d->base_addr = chan->cosa->datareg;
 	d->irq = chan->cosa->irq;
 	d->dma = chan->cosa->dma;
-	d->priv = chan;
+	d->ml_priv = chan;
 	sppp_attach(&chan->pppdev);
 	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
@@ -650,7 +650,7 @@
 
 static int cosa_sppp_open(struct net_device *d)
 {
-	struct channel_data *chan = d->priv;
+	struct channel_data *chan = d->ml_priv;
 	int err;
 	unsigned long flags;
 
@@ -690,7 +690,7 @@
 
 static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = dev->ml_priv;
 
 	netif_stop_queue(dev);
 
@@ -701,7 +701,7 @@
 
 static void cosa_sppp_timeout(struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = dev->ml_priv;
 
 	if (test_bit(RXBIT, &chan->cosa->rxtx)) {
 		chan->stats.rx_errors++;
@@ -720,7 +720,7 @@
 
 static int cosa_sppp_close(struct net_device *d)
 {
-	struct channel_data *chan = d->priv;
+	struct channel_data *chan = d->ml_priv;
 	unsigned long flags;
 
 	netif_stop_queue(d);
@@ -800,7 +800,7 @@
 
 static struct net_device_stats *cosa_net_stats(struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = dev->ml_priv;
 	return &chan->stats;
 }
 
@@ -1217,7 +1217,7 @@
 	int cmd)
 {
 	int rv;
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = dev->ml_priv;
 	rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data);
 	if (rv == -ENOIOCTLCMD) {
 		return sppp_do_ioctl(dev, ifr, cmd);
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 10396d9..0030833 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -45,7 +45,7 @@
 	int (*old_ioctl)(struct net_device *, struct ifreq *, int);
 	int result;
 
-	dev->priv = &state(hdlc)->syncppp_ptr;
+	dev->ml_priv = &state(hdlc)->syncppp_ptr;
 	state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
 	state(hdlc)->pppdev.dev = dev;
 
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 83dbc92..f3065d3 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -75,7 +75,7 @@
  
 static int hostess_open(struct net_device *d)
 {
-	struct sv11_device *sv11=d->priv;
+	struct sv11_device *sv11=d->ml_priv;
 	int err = -1;
 	
 	/*
@@ -128,7 +128,7 @@
 
 static int hostess_close(struct net_device *d)
 {
-	struct sv11_device *sv11=d->priv;
+	struct sv11_device *sv11=d->ml_priv;
 	/*
 	 *	Discard new frames
 	 */
@@ -159,14 +159,14 @@
 
 static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
 {
-	/* struct sv11_device *sv11=d->priv;
+	/* struct sv11_device *sv11=d->ml_priv;
 	   z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
 	return sppp_do_ioctl(d, ifr,cmd);
 }
 
 static struct net_device_stats *hostess_get_stats(struct net_device *d)
 {
-	struct sv11_device *sv11=d->priv;
+	struct sv11_device *sv11=d->ml_priv;
 	if(sv11)
 		return z8530_get_stats(&sv11->sync.chanA);
 	else
@@ -179,7 +179,7 @@
  
 static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d)
 {
-	struct sv11_device *sv11=d->priv;
+	struct sv11_device *sv11=d->ml_priv;
 	return z8530_queue_xmit(&sv11->sync.chanA, skb);
 }
 
@@ -325,6 +325,7 @@
 		/* 
 		 *	Initialise the PPP components
 		 */
+		d->ml_priv = sv;
 		sppp_attach(&sv->netdev);
 		
 		/*
@@ -333,7 +334,6 @@
 		
 		d->base_addr = iobase;
 		d->irq = irq;
-		d->priv = sv;
 		
 		if(register_netdev(d))
 		{
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 6635ece..62133ce 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -891,6 +891,7 @@
 
     /* Initialize the sppp layer */
     /* An ioctl can cause a subsequent detach for raw frame interface */
+    dev->ml_priv = sc;
     sc->if_type = LMC_PPP;
     sc->check = 0xBEAFCAFE;
     dev->base_addr = pci_resource_start(pdev, 0);
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 11276bf..44a89df 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -241,6 +241,7 @@
 		return NULL;
 
 	sv = d->priv;
+	d->ml_priv = sv;
 	sv->if_ptr = &sv->pppdev;
 	sv->pppdev.dev = d;
 	d->base_addr = iobase;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index d340683..62a3d8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -666,7 +666,7 @@
 	rx_status.flag = 0;
 	rx_status.mactime = le64_to_cpu(rx_end->timestamp);
 	rx_status.freq =
-		ieee80211_frequency_to_channel(le16_to_cpu(rx_hdr->channel));
+		ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel));
 	rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
 				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index b608e1c..c9847b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -163,8 +163,8 @@
 	struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
 #endif
 	struct iwl4965_rate dbg_fixed;
-	struct iwl_priv *drv;
 #endif
+	struct iwl_priv *drv;
 };
 
 static void rs_rate_scale_perform(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 17f629f..bf19eb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3978,7 +3978,7 @@
 
 	rx_status.mactime = le64_to_cpu(rx_start->timestamp);
 	rx_status.freq =
-		ieee80211_frequency_to_channel(le16_to_cpu(rx_start->channel));
+		ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel));
 	rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
 				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 	rx_status.rate_idx =
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 04c2638..9196825 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -388,8 +388,15 @@
 
 	netif_start_queue(ndev);
 
-	/* Turn off carrier unless we know we have associated */
-	netif_carrier_off(ndev);
+	/* Turn off carrier if in STA or Ad-hoc mode. It will be turned on
+	 * once the firmware receives a trap of being associated
+	 * (GEN_OID_LINKSTATE). In other modes (AP or WDS or monitor) we
+	 * should just leave the carrier on as its expected the firmware
+	 * won't send us a trigger. */
+	if (priv->iw_mode == IW_MODE_INFRA || priv->iw_mode == IW_MODE_ADHOC)
+		netif_carrier_off(ndev);
+	else
+		netif_carrier_on(ndev);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 8d8657f..b22c027 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1032,8 +1032,10 @@
 	 * Initialize the device.
 	 */
 	status = rt2x00dev->ops->lib->initialize(rt2x00dev);
-	if (status)
-		goto exit;
+	if (status) {
+		rt2x00queue_uninitialize(rt2x00dev);
+		return status;
+	}
 
 	__set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
 
@@ -1043,11 +1045,6 @@
 	rt2x00rfkill_register(rt2x00dev);
 
 	return 0;
-
-exit:
-	rt2x00lib_uninitialize(rt2x00dev);
-
-	return status;
 }
 
 int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 7867ec6..971af25 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -314,13 +314,14 @@
 	if (status) {
 		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
 		      pci_dev->irq, status);
-		return status;
+		goto exit;
 	}
 
 	return 0;
 
 exit:
-	rt2x00pci_uninitialize(rt2x00dev);
+	queue_for_each(rt2x00dev, queue)
+		rt2x00pci_free_queue_dma(rt2x00dev, queue);
 
 	return status;
 }
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index ae12dcd..14bc7b2 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2366,6 +2366,7 @@
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_intf *intf = vif_to_intf(control->vif);
+	struct queue_entry_priv_pci_tx *priv_tx;
 	struct skb_frame_desc *skbdesc;
 	unsigned int beacon_base;
 	u32 reg;
@@ -2373,21 +2374,8 @@
 	if (unlikely(!intf->beacon))
 		return -ENOBUFS;
 
-	/*
-	 * We need to append the descriptor in front of the
-	 * beacon frame.
-	 */
-	if (skb_headroom(skb) < intf->beacon->queue->desc_size) {
-		if (pskb_expand_head(skb, intf->beacon->queue->desc_size,
-				     0, GFP_ATOMIC))
-			return -ENOMEM;
-	}
-
-	/*
-	 * Add the descriptor in front of the skb.
-	 */
-	skb_push(skb, intf->beacon->queue->desc_size);
-	memset(skb->data, 0, intf->beacon->queue->desc_size);
+	priv_tx = intf->beacon->priv_data;
+	memset(priv_tx->desc, 0, intf->beacon->queue->desc_size);
 
 	/*
 	 * Fill in skb descriptor
@@ -2395,9 +2383,9 @@
 	skbdesc = get_skb_frame_desc(skb);
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
-	skbdesc->data = skb->data + intf->beacon->queue->desc_size;
-	skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
-	skbdesc->desc = skb->data;
+	skbdesc->data = skb->data;
+	skbdesc->data_len = skb->len;
+	skbdesc->desc = priv_tx->desc;
 	skbdesc->desc_len = intf->beacon->queue->desc_size;
 	skbdesc->entry = intf->beacon;
 
@@ -2425,7 +2413,10 @@
 	 */
 	beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
 	rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
-				      skb->data, skb->len);
+				      skbdesc->desc, skbdesc->desc_len);
+	rt2x00pci_register_multiwrite(rt2x00dev,
+				      beacon_base + skbdesc->desc_len,
+				      skbdesc->data, skbdesc->data_len);
 	rt61pci_kick_tx_queue(rt2x00dev, control->queue);
 
 	return 0;
@@ -2490,7 +2481,7 @@
 
 static const struct data_queue_desc rt61pci_queue_bcn = {
 	.entry_num		= 4 * BEACON_ENTRIES,
-	.data_size		= MGMT_FRAME_SIZE,
+	.data_size		= 0, /* No DMA required for beacons */
 	.desc_size		= TXINFO_SIZE,
 	.priv_size		= sizeof(struct queue_entry_priv_pci_tx),
 };
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 03384a4..49ae970 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -908,9 +908,9 @@
 	     p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
 	     p->psa_call_code[6], p->psa_call_code[7]);
 #ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n",
 	       p->psa_reserved[0],
-	       p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
+	       p->psa_reserved[1]);
 #endif				/* DEBUG_SHOW_UNUSED */
 	printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
 	printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index baf7401..b584c0e 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1074,11 +1074,9 @@
 	 p->psa_call_code[6],
 	 p->psa_call_code[7]);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n",
 	 p->psa_reserved[0],
-	 p->psa_reserved[1],
-	 p->psa_reserved[2],
-	 p->psa_reserved[3]);
+	 p->psa_reserved[1]);
 #endif	/* DEBUG_SHOW_UNUSED */
   printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
   printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 5316074..12e24f0 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -889,9 +889,13 @@
 	}
 free_urb:
 	skb = (struct sk_buff *)urb->context;
-	zd_mac_tx_to_dev(skb, urb->status);
+	/*
+	 * grab 'usb' pointer before handing off the skb (since
+	 * it might be freed by zd_mac_tx_to_dev or mac80211)
+	 */
 	cb = (struct zd_tx_skb_control_block *)skb->cb;
 	usb = &zd_hw_mac(cb->hw)->chip.usb;
+	zd_mac_tx_to_dev(skb, urb->status);
 	free_tx_urb(usb, urb);
 	tx_dec_submitted_urbs(usb);
 	return;
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 1fd8bb7..66c0fd2 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -49,7 +49,7 @@
 
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
+#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
 
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
 
@@ -490,12 +490,12 @@
 
 #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
 {\
-	unsigned long start_time = jiffies;\
+	cycles_t start_time = get_cycles();\
 	while (1) {\
 		sts = op (iommu->reg + offset);\
 		if (cond)\
 			break;\
-		if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))\
+		if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
 			panic("DMAR hardware is malfunctioning\n");\
 		cpu_relax();\
 	}\
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 72f7476..9d6fc8e 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -19,8 +19,31 @@
 #include <linux/pci-acpi.h>
 #include "pci.h"
 
-static u32 ctrlset_buf[3] = {0, 0, 0};
-static u32 global_ctrlsets = 0;
+struct acpi_osc_data {
+	acpi_handle handle;
+	u32 ctrlset_buf[3];
+	u32 global_ctrlsets;
+	struct list_head sibiling;
+};
+static LIST_HEAD(acpi_osc_data_list);
+
+static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
+{
+	struct acpi_osc_data *data;
+
+	list_for_each_entry(data, &acpi_osc_data_list, sibiling) {
+		if (data->handle == handle)
+			return data;
+	}
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+	INIT_LIST_HEAD(&data->sibiling);
+	data->handle = handle;
+	list_add_tail(&data->sibiling, &acpi_osc_data_list);
+	return data;
+}
+
 static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
 
 static acpi_status  
@@ -37,8 +60,27 @@
 	union acpi_object 	*out_obj;
 	u32			osc_dw0;
 	acpi_status *ret_status = (acpi_status *)retval;
+	struct acpi_osc_data *osc_data;
+	u32 flags = (unsigned long)context, temp;
+	acpi_handle tmp;
 
-	
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	osc_data = acpi_get_osc_data(handle);
+	if (!osc_data) {
+		printk(KERN_ERR "acpi osc data array is full\n");
+		return AE_ERROR;
+	}
+
+	osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
+
+	/* do _OSC query for all possible controls */
+	temp = osc_data->ctrlset_buf[OSC_CONTROL_TYPE];
+	osc_data->ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+	osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+
 	/* Setting up input parameters */
 	input.count = 4;
 	input.pointer = in_params;
@@ -51,13 +93,11 @@
 	in_params[2].integer.value	= 3;
 	in_params[3].type		= ACPI_TYPE_BUFFER;
 	in_params[3].buffer.length 	= 12;
-	in_params[3].buffer.pointer 	= (u8 *)context;
+	in_params[3].buffer.pointer 	= (u8 *)osc_data->ctrlset_buf;
 
 	status = acpi_evaluate_object(handle, "_OSC", &input, &output);
-	if (ACPI_FAILURE (status)) {
-		*ret_status = status;
-		return status;
-	}
+	if (ACPI_FAILURE(status))
+		goto out_nofree;
 	out_obj = output.pointer;
 
 	if (out_obj->type != ACPI_TYPE_BUFFER) {
@@ -76,7 +116,8 @@
 			printk(KERN_DEBUG "_OSC invalid revision\n"); 
 		if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
 			/* Update Global Control Set */
-			global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8));
+			osc_data->global_ctrlsets =
+				*((u32 *)(out_obj->buffer.pointer + 8));
 			status = AE_OK;
 			goto query_osc_out;
 		}
@@ -85,12 +126,21 @@
 	}
 
 	/* Update Global Control Set */
-	global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
+	osc_data->global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
 	status = AE_OK;
 
 query_osc_out:
 	kfree(output.pointer);
+out_nofree:
 	*ret_status = status;
+
+	osc_data->ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
+	osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = temp;
+	if (ACPI_FAILURE(status)) {
+		/* no osc support at all */
+		osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
+	}
+
 	return status;
 }
 
@@ -165,28 +215,15 @@
  **/
 acpi_status __pci_osc_support_set(u32 flags, const char *hid)
 {
-	u32 temp;
-	acpi_status retval;
+	acpi_status retval = AE_NOT_FOUND;
 
 	if (!(flags & OSC_SUPPORT_MASKS)) {
 		return AE_TYPE;
 	}
-	ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
-
-	/* do _OSC query for all possible controls */
-	temp = ctrlset_buf[OSC_CONTROL_TYPE];
-	ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
 	acpi_get_devices(hid,
 			acpi_query_osc,
-			ctrlset_buf,
+			(void *)(unsigned long)flags,
 			(void **) &retval );
-	ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
-	ctrlset_buf[OSC_CONTROL_TYPE] = temp;
-	if (ACPI_FAILURE(retval)) {
-		/* no osc support at all */
-		ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
-	}
 	return AE_OK;
 }
 
@@ -201,19 +238,31 @@
 {
 	acpi_status	status;
 	u32		ctrlset;
+	acpi_handle tmp;
+	struct acpi_osc_data *osc_data;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	osc_data = acpi_get_osc_data(handle);
+	if (!osc_data) {
+		printk(KERN_ERR "acpi osc data array is full\n");
+		return AE_ERROR;
+	}
 
 	ctrlset = (flags & OSC_CONTROL_MASKS);
 	if (!ctrlset) {
 		return AE_TYPE;
 	}
-	if (ctrlset_buf[OSC_SUPPORT_TYPE] && 
-	 	((global_ctrlsets & ctrlset) != ctrlset)) {
+	if (osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] &&
+		((osc_data->global_ctrlsets & ctrlset) != ctrlset)) {
 		return AE_SUPPORT;
 	}
-	ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
-	status = acpi_run_osc(handle, ctrlset_buf);
+	osc_data->ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
+	status = acpi_run_osc(handle, osc_data->ctrlset_buf);
 	if (ACPI_FAILURE (status)) {
-		ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
+		osc_data->ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
 	}
 	
 	return status;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index afd914e..f2d9c77 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1826,6 +1826,7 @@
 	}
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
 
 static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 5d9301d..5695a79 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -424,7 +424,7 @@
 				start = simple_strtoul(buf, &buf, 0);
 				pnp_res = pnp_add_irq_resource(dev, start, 0);
 				if (pnp_res)
-					nirq++;
+					pnp_res->index = nirq++;
 				continue;
 			}
 			if (!strnicmp(buf, "dma", 3)) {
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index ba795a4..9f996ec 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -51,7 +51,7 @@
  */
 void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
 {
-	register int days, month, year;
+	unsigned int days, month, year;
 
 	days = time / 86400;
 	time -= days * 86400;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 316bfaa..a3e0880 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -15,6 +15,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/i2c.h>
@@ -803,6 +804,7 @@
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
 	if (clientdata->features & M41T80_FEATURE_HT) {
+		save_client = client;
 		rc = misc_register(&wdt_dev);
 		if (rc)
 			goto exit;
@@ -811,7 +813,6 @@
 			misc_deregister(&wdt_dev);
 			goto exit;
 		}
-		save_client = client;
 	}
 #endif
 	return 0;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index f5215fd..1dca177 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -3830,7 +3830,7 @@
 			iounmap(p);
 		}
 		if (!ok && setup_count == 0)
-			return 0;
+			return -ENODEV;
 
 		printk(KERN_INFO "aha152x: BIOS test: passed, ");
 #else
@@ -3909,14 +3909,14 @@
 #endif
 	}
 
-	return 1;
+	return 0;
 }
 
 static void __exit aha152x_exit(void)
 {
-	struct aha152x_hostdata *hd;
+	struct aha152x_hostdata *hd, *tmp;
 
-	list_for_each_entry(hd, &aha152x_host_list, host_list) {
+	list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
 		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
 
 		aha152x_release(shost);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 8e2e964..46771d4 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -550,7 +550,6 @@
 #endif /* CONFIG_ISA */
 
 #ifdef CONFIG_PCI
-static bool gdth_pci_registered;
 
 static bool gdth_search_vortex(ushort device)
 {
@@ -3724,6 +3723,8 @@
 }
 
 #ifdef GDTH_STATISTICS
+static unchar	gdth_timer_running;
+
 static void gdth_timeout(ulong data)
 {
     ulong32 i;
@@ -3731,7 +3732,10 @@
     gdth_ha_str *ha;
     ulong flags;
 
-    BUG_ON(list_empty(&gdth_instances));
+    if(unlikely(list_empty(&gdth_instances))) {
+	    gdth_timer_running = 0;
+	    return;
+    }
 
     ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
     spin_lock_irqsave(&ha->smp_lock, flags);
@@ -3751,6 +3755,22 @@
     add_timer(&gdth_timer);
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
+
+static void gdth_timer_init(void)
+{
+	if (gdth_timer_running)
+		return;
+	gdth_timer_running = 1;
+	TRACE2(("gdth_detect(): Initializing timer !\n"));
+	gdth_timer.expires = jiffies + HZ;
+	gdth_timer.data = 0L;
+	gdth_timer.function = gdth_timeout;
+	add_timer(&gdth_timer);
+}
+#else
+static inline void gdth_timer_init(void)
+{
+}
 #endif
 
 static void __init internal_setup(char *str,int *ints)
@@ -4735,6 +4755,7 @@
 	if (error)
 		goto out_free_coal_stat;
 	list_add_tail(&ha->list, &gdth_instances);
+	gdth_timer_init();
 
 	scsi_scan_host(shp);
 
@@ -4865,6 +4886,7 @@
 	if (error)
 		goto out_free_coal_stat;
 	list_add_tail(&ha->list, &gdth_instances);
+	gdth_timer_init();
 
 	scsi_scan_host(shp);
 
@@ -5011,6 +5033,7 @@
 	list_add_tail(&ha->list, &gdth_instances);
 
 	pci_set_drvdata(ha->pdev, ha);
+	gdth_timer_init();
 
 	scsi_scan_host(shp);
 
@@ -5110,6 +5133,7 @@
 	/* initializations */
 	gdth_polling = TRUE;
 	gdth_clear_events();
+	init_timer(&gdth_timer);
 
 	/* As default we do not probe for EISA or ISA controllers */
 	if (probe_eisa_isa) {
@@ -5132,23 +5156,17 @@
 
 #ifdef CONFIG_PCI
 	/* scanning for PCI controllers */
-	if (pci_register_driver(&gdth_pci_driver) == 0)
-		gdth_pci_registered = true;
+	if (pci_register_driver(&gdth_pci_driver)) {
+		gdth_ha_str *ha;
+
+		list_for_each_entry(ha, &gdth_instances, list)
+			gdth_remove_one(ha);
+		return -ENODEV;
+	}
 #endif /* CONFIG_PCI */
 
 	TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count));
 
-	if (list_empty(&gdth_instances))
-		return -ENODEV;
-
-#ifdef GDTH_STATISTICS
-	TRACE2(("gdth_detect(): Initializing timer !\n"));
-	init_timer(&gdth_timer);
-	gdth_timer.expires = jiffies + HZ;
-	gdth_timer.data = 0L;
-	gdth_timer.function = gdth_timeout;
-	add_timer(&gdth_timer);
-#endif
 	major = register_chrdev(0,"gdth", &gdth_fops);
 	register_reboot_notifier(&gdth_notifier);
 	gdth_polling = FALSE;
@@ -5167,8 +5185,7 @@
 #endif
 
 #ifdef CONFIG_PCI
-	if (gdth_pci_registered)
-		pci_unregister_driver(&gdth_pci_driver);
+	pci_unregister_driver(&gdth_pci_driver);
 #endif
 
 	list_for_each_entry(ha, &gdth_instances, list)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 010c1b9..b43bf1d 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -730,7 +730,9 @@
 				if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
 						   datalen))
 					rc = ISCSI_ERR_CONN_FAILED;
-			}
+			} else
+				mod_timer(&conn->transport_timer,
+					  jiffies + conn->recv_timeout);
 			iscsi_free_mgmt_task(conn, mtask);
 			break;
 		default:
@@ -1453,19 +1455,20 @@
 {
 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
 	struct iscsi_session *session = conn->session;
-	unsigned long timeout, next_timeout = 0, last_recv;
+	unsigned long recv_timeout, next_timeout = 0, last_recv;
 
 	spin_lock(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN)
 		goto done;
 
-	timeout = conn->recv_timeout;
-	if (!timeout)
+	recv_timeout = conn->recv_timeout;
+	if (!recv_timeout)
 		goto done;
 
-	timeout *= HZ;
+	recv_timeout *= HZ;
 	last_recv = conn->last_recv;
-	if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
+	if (conn->ping_mtask &&
+	    time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
 			   jiffies)) {
 		iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
 				  "expired, last rx %lu, last ping %lu, "
@@ -1476,15 +1479,13 @@
 		return;
 	}
 
-	if (time_before_eq(last_recv + timeout, jiffies)) {
-		if (time_before_eq(conn->last_ping, last_recv)) {
-			/* send a ping to try to provoke some traffic */
-			debug_scsi("Sending nopout as ping on conn %p\n", conn);
-			iscsi_send_nopout(conn, NULL);
-		}
-		next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
+	if (time_before_eq(last_recv + recv_timeout, jiffies)) {
+		/* send a ping to try to provoke some traffic */
+		debug_scsi("Sending nopout as ping on conn %p\n", conn);
+		iscsi_send_nopout(conn, NULL);
+		next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
 	} else
-		next_timeout = last_recv + timeout;
+		next_timeout = last_recv + recv_timeout;
 
 	debug_scsi("Setting next tmo %lu\n", next_timeout);
 	mod_timer(&conn->transport_timer, next_timeout);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index fa06093..51e2f29 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2007,7 +2007,7 @@
 		nv->bus[bus].config_2.req_ack_active_negation = 1;
 		nv->bus[bus].config_2.data_line_active_negation = 1;
 		nv->bus[bus].selection_timeout = 250;
-		nv->bus[bus].max_queue_depth = 256;
+		nv->bus[bus].max_queue_depth = 32;
 
 		if (IS_ISP1040(ha)) {
 			nv->bus[bus].bus_reset_delay = 3;
@@ -2051,7 +2051,7 @@
 	status = qla1280_mailbox_command(ha, 0x0f, mb);
 
 	/* Save Tag queuing enable flag. */
-	flag = (BIT_0 << target) & mb[0];
+	flag = (BIT_0 << target);
 	if (nv->bus[bus].target[target].parameter.tag_queuing)
 		ha->bus_settings[bus].qtag_enables |= flag;
 
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index fae9e8f..66ec5d8 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -126,7 +126,6 @@
 config SPI_MPC83xx
 	tristate "Freescale MPC83xx/QUICC Engine SPI controller"
 	depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
-	select SPI_BITBANG
 	help
 	  This enables using the Freescale MPC83xx and QUICC Engine SPI
 	  controllers in master mode.
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 654bb58..0c452c4 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1567,7 +1567,7 @@
 	int status = 0;
 
 	/* Enable the SSP clock */
-	clk_disable(ssp->clk);
+	clk_enable(ssp->clk);
 
 	/* Start the queue running */
 	status = start_queue(drv_data);
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 189f706..6832da6 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -49,6 +49,7 @@
 #define	SPMODE_LEN(x)		((x) << 20)
 #define	SPMODE_PM(x)		((x) << 16)
 #define	SPMODE_OP		(1 << 14)
+#define	SPMODE_CG(x)		((x) << 7)
 
 /*
  * Default for SPI Mode:
@@ -67,10 +68,6 @@
 
 /* SPI Controller driver's private data. */
 struct mpc83xx_spi {
-	/* bitbang has to be first */
-	struct spi_bitbang bitbang;
-	struct completion done;
-
 	struct mpc83xx_spi_reg __iomem *base;
 
 	/* rx & tx bufs from the spi_transfer */
@@ -82,7 +79,7 @@
 	u32(*get_tx) (struct mpc83xx_spi *);
 
 	unsigned int count;
-	u32 irq;
+	int irq;
 
 	unsigned nsecs;		/* (clock cycle time)/2 */
 
@@ -94,6 +91,25 @@
 
 	void (*activate_cs) (u8 cs, u8 polarity);
 	void (*deactivate_cs) (u8 cs, u8 polarity);
+
+	u8 busy;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;
+
+	struct completion done;
+};
+
+struct spi_mpc83xx_cs {
+	/* functions to deal with different sized buffers */
+	void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
+	u32 (*get_tx) (struct mpc83xx_spi *);
+	u32 rx_shift;		/* RX data reg shift when in qe mode */
+	u32 tx_shift;		/* TX data reg shift when in qe mode */
+	u32 hw_mode;		/* Holds HW mode register settings */
 };
 
 static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
@@ -137,6 +153,7 @@
 {
 	struct mpc83xx_spi *mpc83xx_spi;
 	u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+	struct spi_mpc83xx_cs	*cs = spi->controller_state;
 
 	mpc83xx_spi = spi_master_get_devdata(spi->master);
 
@@ -147,50 +164,26 @@
 
 	if (value == BITBANG_CS_ACTIVE) {
 		u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
-		u32 len = spi->bits_per_word;
-		u8 pm;
 
-		if (len == 32)
-			len = 0;
-		else
-			len = len - 1;
+		mpc83xx_spi->rx_shift = cs->rx_shift;
+		mpc83xx_spi->tx_shift = cs->tx_shift;
+		mpc83xx_spi->get_rx = cs->get_rx;
+		mpc83xx_spi->get_tx = cs->get_tx;
 
-		/* mask out bits we are going to set */
-		regval &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
-				| SPMODE_LEN(0xF) | SPMODE_DIV16
-				| SPMODE_PM(0xF) | SPMODE_REV | SPMODE_LOOP);
+		if (cs->hw_mode != regval) {
+			unsigned long flags;
+			void *tmp_ptr = &mpc83xx_spi->base->mode;
 
-		if (spi->mode & SPI_CPHA)
-			regval |= SPMODE_CP_BEGIN_EDGECLK;
-		if (spi->mode & SPI_CPOL)
-			regval |= SPMODE_CI_INACTIVEHIGH;
-		if (!(spi->mode & SPI_LSB_FIRST))
-			regval |= SPMODE_REV;
-		if (spi->mode & SPI_LOOP)
-			regval |= SPMODE_LOOP;
-
-		regval |= SPMODE_LEN(len);
-
-		if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
-			pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
-			if (pm > 0x0f) {
-				dev_err(&spi->dev, "Requested speed is too "
-					"low: %d Hz. Will use %d Hz instead.\n",
-					spi->max_speed_hz,
-					mpc83xx_spi->spibrg / 1024);
-				pm = 0x0f;
-			}
-			regval |= SPMODE_PM(pm) | SPMODE_DIV16;
-		} else {
-			pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
-			if (pm)
-				pm--;
-			regval |= SPMODE_PM(pm);
+			regval = cs->hw_mode;
+			/* Turn off IRQs locally to minimize time that
+			 * SPI is disabled
+			 */
+			local_irq_save(flags);
+			/* Turn off SPI unit prior changing mode */
+			mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
+			mpc83xx_spi_write_reg(tmp_ptr, regval);
+			local_irq_restore(flags);
 		}
-
-		/* Turn off SPI unit prior changing mode */
-		mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
-		mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
 		if (mpc83xx_spi->activate_cs)
 			mpc83xx_spi->activate_cs(spi->chip_select, pol);
 	}
@@ -201,8 +194,9 @@
 {
 	struct mpc83xx_spi *mpc83xx_spi;
 	u32 regval;
-	u8 bits_per_word;
+	u8 bits_per_word, pm;
 	u32 hz;
+	struct spi_mpc83xx_cs	*cs = spi->controller_state;
 
 	mpc83xx_spi = spi_master_get_devdata(spi->master);
 
@@ -223,122 +217,106 @@
 	    || ((bits_per_word > 16) && (bits_per_word != 32)))
 		return -EINVAL;
 
-	mpc83xx_spi->rx_shift = 0;
-	mpc83xx_spi->tx_shift = 0;
+	if (!hz)
+		hz = spi->max_speed_hz;
+
+	cs->rx_shift = 0;
+	cs->tx_shift = 0;
 	if (bits_per_word <= 8) {
-		mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
-		mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+		cs->get_rx = mpc83xx_spi_rx_buf_u8;
+		cs->get_tx = mpc83xx_spi_tx_buf_u8;
 		if (mpc83xx_spi->qe_mode) {
-			mpc83xx_spi->rx_shift = 16;
-			mpc83xx_spi->tx_shift = 24;
+			cs->rx_shift = 16;
+			cs->tx_shift = 24;
 		}
 	} else if (bits_per_word <= 16) {
-		mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16;
-		mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16;
+		cs->get_rx = mpc83xx_spi_rx_buf_u16;
+		cs->get_tx = mpc83xx_spi_tx_buf_u16;
 		if (mpc83xx_spi->qe_mode) {
-			mpc83xx_spi->rx_shift = 16;
-			mpc83xx_spi->tx_shift = 16;
+			cs->rx_shift = 16;
+			cs->tx_shift = 16;
 		}
 	} else if (bits_per_word <= 32) {
-		mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32;
-		mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32;
+		cs->get_rx = mpc83xx_spi_rx_buf_u32;
+		cs->get_tx = mpc83xx_spi_tx_buf_u32;
 	} else
 		return -EINVAL;
 
 	if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
-		mpc83xx_spi->tx_shift = 0;
+		cs->tx_shift = 0;
 		if (bits_per_word <= 8)
-			mpc83xx_spi->rx_shift = 8;
+			cs->rx_shift = 8;
 		else
-			mpc83xx_spi->rx_shift = 0;
+			cs->rx_shift = 0;
 	}
 
-	/* nsecs = (clock period)/2 */
-	if (!hz)
-		hz = spi->max_speed_hz;
-	mpc83xx_spi->nsecs = (1000000000 / 2) / hz;
-	if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000)
-		return -EINVAL;
+	mpc83xx_spi->rx_shift = cs->rx_shift;
+	mpc83xx_spi->tx_shift = cs->tx_shift;
+	mpc83xx_spi->get_rx = cs->get_rx;
+	mpc83xx_spi->get_tx = cs->get_tx;
 
 	if (bits_per_word == 32)
 		bits_per_word = 0;
 	else
 		bits_per_word = bits_per_word - 1;
 
-	regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
-
 	/* mask out bits we are going to set */
-	regval &= ~(SPMODE_LEN(0xF) | SPMODE_REV);
-	regval |= SPMODE_LEN(bits_per_word);
-	if (!(spi->mode & SPI_LSB_FIRST))
-		regval |= SPMODE_REV;
+	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
+				  | SPMODE_PM(0xF));
 
-	/* Turn off SPI unit prior changing mode */
-	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
-	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+	cs->hw_mode |= SPMODE_LEN(bits_per_word);
 
-	return 0;
-}
-
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
-			| SPI_LSB_FIRST | SPI_LOOP)
-
-static int mpc83xx_spi_setup(struct spi_device *spi)
-{
-	struct spi_bitbang *bitbang;
-	struct mpc83xx_spi *mpc83xx_spi;
-	int retval;
-
-	if (spi->mode & ~MODEBITS) {
-		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
-			spi->mode & ~MODEBITS);
-		return -EINVAL;
+	if ((mpc83xx_spi->spibrg / hz) >= 64) {
+		pm = mpc83xx_spi->spibrg / (hz * 64) - 1;
+		if (pm > 0x0f) {
+			dev_err(&spi->dev, "Requested speed is too "
+				"low: %d Hz. Will use %d Hz instead.\n",
+				hz, mpc83xx_spi->spibrg / 1024);
+			pm = 0x0f;
+		}
+		cs->hw_mode |= SPMODE_PM(pm) | SPMODE_DIV16;
+	} else {
+		pm = mpc83xx_spi->spibrg / (hz * 4);
+		if (pm)
+			pm--;
+		cs->hw_mode |= SPMODE_PM(pm);
 	}
+	regval =  mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+	if (cs->hw_mode != regval) {
+		unsigned long flags;
+		void *tmp_ptr = &mpc83xx_spi->base->mode;
 
-	if (!spi->max_speed_hz)
-		return -EINVAL;
-
-	bitbang = spi_master_get_devdata(spi->master);
-	mpc83xx_spi = spi_master_get_devdata(spi->master);
-
-	if (!spi->bits_per_word)
-		spi->bits_per_word = 8;
-
-	retval = mpc83xx_spi_setup_transfer(spi, NULL);
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
-		__func__, spi->mode & (SPI_CPOL | SPI_CPHA),
-		spi->bits_per_word, 2 * mpc83xx_spi->nsecs);
-
-	/* NOTE we _need_ to call chipselect() early, ideally with adapter
-	 * setup, unless the hardware defaults cooperate to avoid confusion
-	 * between normal (active low) and inverted chipselects.
-	 */
-
-	/* deselect chip (low or high) */
-	spin_lock(&bitbang->lock);
-	if (!bitbang->busy) {
-		bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-		ndelay(mpc83xx_spi->nsecs);
+		regval = cs->hw_mode;
+		/* Turn off IRQs locally to minimize time
+		 * that SPI is disabled
+		 */
+		local_irq_save(flags);
+		/* Turn off SPI unit prior changing mode */
+		mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
+		mpc83xx_spi_write_reg(tmp_ptr, regval);
+		local_irq_restore(flags);
 	}
-	spin_unlock(&bitbang->lock);
-
 	return 0;
 }
 
 static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 {
 	struct mpc83xx_spi *mpc83xx_spi;
-	u32 word;
+	u32 word, len, bits_per_word;
 
 	mpc83xx_spi = spi_master_get_devdata(spi->master);
 
 	mpc83xx_spi->tx = t->tx_buf;
 	mpc83xx_spi->rx = t->rx_buf;
-	mpc83xx_spi->count = t->len;
+	bits_per_word = spi->bits_per_word;
+	if (t->bits_per_word)
+		bits_per_word = t->bits_per_word;
+	len = t->len;
+	if (bits_per_word > 8)
+		len /= 2;
+	if (bits_per_word > 16)
+		len /= 2;
+	mpc83xx_spi->count = len;
 	INIT_COMPLETION(mpc83xx_spi->done);
 
 	/* enable rx ints */
@@ -353,7 +331,147 @@
 	/* disable rx ints */
 	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
 
-	return t->len - mpc83xx_spi->count;
+	return mpc83xx_spi->count;
+}
+
+static void mpc83xx_spi_work(struct work_struct *work)
+{
+	struct mpc83xx_spi *mpc83xx_spi =
+		container_of(work, struct mpc83xx_spi, work);
+
+	spin_lock_irq(&mpc83xx_spi->lock);
+	mpc83xx_spi->busy = 1;
+	while (!list_empty(&mpc83xx_spi->queue)) {
+		struct spi_message *m;
+		struct spi_device *spi;
+		struct spi_transfer *t = NULL;
+		unsigned cs_change;
+		int status, nsecs = 50;
+
+		m = container_of(mpc83xx_spi->queue.next,
+				struct spi_message, queue);
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mpc83xx_spi->lock);
+
+		spi = m->spi;
+		cs_change = 1;
+		status = 0;
+		list_for_each_entry(t, &m->transfers, transfer_list) {
+			if (t->bits_per_word || t->speed_hz) {
+				/* Don't allow changes if CS is active */
+				status = -EINVAL;
+
+				if (cs_change)
+					status = mpc83xx_spi_setup_transfer(spi, t);
+				if (status < 0)
+					break;
+			}
+
+			if (cs_change)
+				mpc83xx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+			cs_change = t->cs_change;
+			if (t->len)
+				status = mpc83xx_spi_bufs(spi, t);
+			if (status) {
+				status = -EMSGSIZE;
+				break;
+			}
+			m->actual_length += t->len;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (cs_change) {
+				ndelay(nsecs);
+				mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+				ndelay(nsecs);
+			}
+		}
+
+		m->status = status;
+		m->complete(m->context);
+
+		if (status || !cs_change) {
+			ndelay(nsecs);
+			mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+		}
+
+		mpc83xx_spi_setup_transfer(spi, NULL);
+
+		spin_lock_irq(&mpc83xx_spi->lock);
+	}
+	mpc83xx_spi->busy = 0;
+	spin_unlock_irq(&mpc83xx_spi->lock);
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+			| SPI_LSB_FIRST | SPI_LOOP)
+
+static int mpc83xx_spi_setup(struct spi_device *spi)
+{
+	struct mpc83xx_spi *mpc83xx_spi;
+	int retval;
+	u32 hw_mode;
+	struct spi_mpc83xx_cs	*cs = spi->controller_state;
+
+	if (spi->mode & ~MODEBITS) {
+		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+			spi->mode & ~MODEBITS);
+		return -EINVAL;
+	}
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+	mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	hw_mode = cs->hw_mode; /* Save orginal settings */
+	cs->hw_mode = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+	/* mask out bits we are going to set */
+	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
+			 | SPMODE_REV | SPMODE_LOOP);
+
+	if (spi->mode & SPI_CPHA)
+		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
+	if (spi->mode & SPI_CPOL)
+		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
+	if (!(spi->mode & SPI_LSB_FIRST))
+		cs->hw_mode |= SPMODE_REV;
+	if (spi->mode & SPI_LOOP)
+		cs->hw_mode |= SPMODE_LOOP;
+
+	retval = mpc83xx_spi_setup_transfer(spi, NULL);
+	if (retval < 0) {
+		cs->hw_mode = hw_mode; /* Restore settings */
+		return retval;
+	}
+
+	dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n",
+		__func__, spi->mode & (SPI_CPOL | SPI_CPHA),
+		spi->bits_per_word, spi->max_speed_hz);
+#if 0 /* Don't think this is needed */
+	/* NOTE we _need_ to call chipselect() early, ideally with adapter
+	 * setup, unless the hardware defaults cooperate to avoid confusion
+	 * between normal (active low) and inverted chipselects.
+	 */
+
+	/* deselect chip (low or high) */
+	spin_lock(&mpc83xx_spi->lock);
+	if (!mpc83xx_spi->busy)
+		mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+	spin_unlock(&mpc83xx_spi->lock);
+#endif
+	return 0;
 }
 
 irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
@@ -395,6 +513,28 @@
 
 	return ret;
 }
+static int mpc83xx_spi_transfer(struct spi_device *spi,
+				struct spi_message *m)
+{
+	struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mpc83xx_spi->lock, flags);
+	list_add_tail(&m->queue, &mpc83xx_spi->queue);
+	queue_work(mpc83xx_spi->workqueue, &mpc83xx_spi->work);
+	spin_unlock_irqrestore(&mpc83xx_spi->lock, flags);
+
+	return 0;
+}
+
+
+static void mpc83xx_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
 
 static int __init mpc83xx_spi_probe(struct platform_device *dev)
 {
@@ -426,11 +566,11 @@
 		ret = -ENODEV;
 		goto free_master;
 	}
+	master->setup = mpc83xx_spi_setup;
+	master->transfer = mpc83xx_spi_transfer;
+	master->cleanup = mpc83xx_spi_cleanup;
+
 	mpc83xx_spi = spi_master_get_devdata(master);
-	mpc83xx_spi->bitbang.master = spi_master_get(master);
-	mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
-	mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
-	mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
 	mpc83xx_spi->activate_cs = pdata->activate_cs;
 	mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
 	mpc83xx_spi->qe_mode = pdata->qe_mode;
@@ -445,7 +585,6 @@
 		mpc83xx_spi->tx_shift = 24;
 	}
 
-	mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
 	init_completion(&mpc83xx_spi->done);
 
 	mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
@@ -483,11 +622,21 @@
 		regval |= SPMODE_OP;
 
 	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+	spin_lock_init(&mpc83xx_spi->lock);
+	init_completion(&mpc83xx_spi->done);
+	INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work);
+	INIT_LIST_HEAD(&mpc83xx_spi->queue);
 
-	ret = spi_bitbang_start(&mpc83xx_spi->bitbang);
-
-	if (ret != 0)
+	mpc83xx_spi->workqueue = create_singlethread_workqueue(
+		master->dev.parent->bus_id);
+	if (mpc83xx_spi->workqueue == NULL) {
+		ret = -EBUSY;
 		goto free_irq;
+	}
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
 
 	printk(KERN_INFO
 	       "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
@@ -495,6 +644,8 @@
 
 	return ret;
 
+unreg_master:
+	destroy_workqueue(mpc83xx_spi->workqueue);
 free_irq:
 	free_irq(mpc83xx_spi->irq, mpc83xx_spi);
 unmap_io:
@@ -515,10 +666,12 @@
 	master = platform_get_drvdata(dev);
 	mpc83xx_spi = spi_master_get_devdata(master);
 
-	spi_bitbang_stop(&mpc83xx_spi->bitbang);
+	flush_workqueue(mpc83xx_spi->workqueue);
+	destroy_workqueue(mpc83xx_spi->workqueue);
+	spi_unregister_master(master);
+
 	free_irq(mpc83xx_spi->irq, mpc83xx_spi);
 	iounmap(mpc83xx_spi->base);
-	spi_master_put(mpc83xx_spi->bitbang.master);
 
 	return 0;
 }
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index cefe7f2..63c3404 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1248,6 +1248,9 @@
 	{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
+	{ USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
+	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+	},
 
 	/* control interfaces with various AT-command sets */
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 99e5a68..fae55a3 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -156,6 +156,10 @@
 static struct attribute_group ep_dev_attr_grp = {
 	.attrs = ep_dev_attrs,
 };
+static struct attribute_group *ep_dev_groups[] = {
+	&ep_dev_attr_grp,
+	NULL
+};
 
 static int usb_endpoint_major_init(void)
 {
@@ -298,6 +302,7 @@
 
 	ep_dev->desc = &endpoint->desc;
 	ep_dev->udev = udev;
+	ep_dev->dev.groups = ep_dev_groups;
 	ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
 	ep_dev->dev.class = ep_class->class;
 	ep_dev->dev.parent = parent;
@@ -309,9 +314,6 @@
 	retval = device_register(&ep_dev->dev);
 	if (retval)
 		goto error_chrdev;
-	retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
-	if (retval)
-		goto error_group;
 
 	/* create the symlink to the old-style "ep_XX" directory */
 	sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
@@ -322,8 +324,6 @@
 	return retval;
 
 error_link:
-	sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
-error_group:
 	device_unregister(&ep_dev->dev);
 	destroy_endpoint_class();
 	return retval;
@@ -348,7 +348,6 @@
 
 		sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
 		sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
-		sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
 		device_unregister(&ep_dev->dev);
 		endpoint->ep_dev = NULL;
 		destroy_endpoint_class();
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 3e69266..fe47d14 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1607,6 +1607,7 @@
 		intf->dev.driver = NULL;
 		intf->dev.bus = &usb_bus_type;
 		intf->dev.type = &usb_if_device_type;
+		intf->dev.groups = usb_interface_groups;
 		intf->dev.dma_mask = dev->dev.dma_mask;
 		device_initialize(&intf->dev);
 		mark_quiesced(intf);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5b20a60..c783cb1 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -538,6 +538,46 @@
 	.attrs = dev_attrs,
 };
 
+/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
+ * accordingly.
+ */
+static struct attribute *dev_string_attrs[] = {
+	&dev_attr_manufacturer.attr,
+	&dev_attr_product.attr,
+	&dev_attr_serial.attr,
+	NULL
+};
+
+static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
+		struct attribute *a, int n)
+{
+	struct usb_device *udev = to_usb_device(
+			container_of(kobj, struct device, kobj));
+
+	if (a == &dev_attr_manufacturer.attr) {
+		if (udev->manufacturer == NULL)
+			return 0;
+	} else if (a == &dev_attr_product.attr) {
+		if (udev->product == NULL)
+			return 0;
+	} else if (a == &dev_attr_serial.attr) {
+		if (udev->serial == NULL)
+			return 0;
+	}
+	return a->mode;
+}
+
+static struct attribute_group dev_string_attr_grp = {
+	.attrs =	dev_string_attrs,
+	.is_visible =	dev_string_attrs_are_visible,
+};
+
+struct attribute_group *usb_device_groups[] = {
+	&dev_attr_grp,
+	&dev_string_attr_grp,
+	NULL
+};
+
 /* Binary descriptors */
 
 static ssize_t
@@ -591,10 +631,9 @@
 	struct device *dev = &udev->dev;
 	int retval;
 
-	retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
-	if (retval)
-		return retval;
-
+	/* Unforunately these attributes cannot be created before
+	 * the uevent is broadcast.
+	 */
 	retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
 	if (retval)
 		goto error;
@@ -607,21 +646,6 @@
 	if (retval)
 		goto error;
 
-	if (udev->manufacturer) {
-		retval = device_create_file(dev, &dev_attr_manufacturer);
-		if (retval)
-			goto error;
-	}
-	if (udev->product) {
-		retval = device_create_file(dev, &dev_attr_product);
-		if (retval)
-			goto error;
-	}
-	if (udev->serial) {
-		retval = device_create_file(dev, &dev_attr_serial);
-		if (retval)
-			goto error;
-	}
 	retval = usb_create_ep_files(dev, &udev->ep0, udev);
 	if (retval)
 		goto error;
@@ -636,13 +660,9 @@
 	struct device *dev = &udev->dev;
 
 	usb_remove_ep_files(&udev->ep0);
-	device_remove_file(dev, &dev_attr_manufacturer);
-	device_remove_file(dev, &dev_attr_product);
-	device_remove_file(dev, &dev_attr_serial);
 	remove_power_attributes(dev);
 	remove_persist_attributes(dev);
 	device_remove_bin_file(dev, &dev_bin_attr_descriptors);
-	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
 /* Interface Accociation Descriptor fields */
@@ -688,17 +708,15 @@
 		struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf;
-	struct usb_device *udev;
-	int len;
+	char *string;
 
 	intf = to_usb_interface(dev);
-	udev = interface_to_usbdev(intf);
-	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
-	if (len < 0)
+	string = intf->cur_altsetting->string;
+	barrier();		/* The altsetting might change! */
+
+	if (!string)
 		return 0;
-	buf[len] = '\n';
-	buf[len+1] = 0;
-	return len+1;
+	return sprintf(buf, "%s\n", string);
 }
 static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
 
@@ -727,18 +745,6 @@
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
-static struct attribute *intf_assoc_attrs[] = {
-	&dev_attr_iad_bFirstInterface.attr,
-	&dev_attr_iad_bInterfaceCount.attr,
-	&dev_attr_iad_bFunctionClass.attr,
-	&dev_attr_iad_bFunctionSubClass.attr,
-	&dev_attr_iad_bFunctionProtocol.attr,
-	NULL,
-};
-static struct attribute_group intf_assoc_attr_grp = {
-	.attrs = intf_assoc_attrs,
-};
-
 static struct attribute *intf_attrs[] = {
 	&dev_attr_bInterfaceNumber.attr,
 	&dev_attr_bAlternateSetting.attr,
@@ -753,6 +759,37 @@
 	.attrs = intf_attrs,
 };
 
+static struct attribute *intf_assoc_attrs[] = {
+	&dev_attr_iad_bFirstInterface.attr,
+	&dev_attr_iad_bInterfaceCount.attr,
+	&dev_attr_iad_bFunctionClass.attr,
+	&dev_attr_iad_bFunctionSubClass.attr,
+	&dev_attr_iad_bFunctionProtocol.attr,
+	NULL,
+};
+
+static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
+		struct attribute *a, int n)
+{
+	struct usb_interface *intf = to_usb_interface(
+			container_of(kobj, struct device, kobj));
+
+	if (intf->intf_assoc == NULL)
+		return 0;
+	return a->mode;
+}
+
+static struct attribute_group intf_assoc_attr_grp = {
+	.attrs =	intf_assoc_attrs,
+	.is_visible =	intf_assoc_attrs_are_visible,
+};
+
+struct attribute_group *usb_interface_groups[] = {
+	&intf_attr_grp,
+	&intf_assoc_attr_grp,
+	NULL
+};
+
 static inline void usb_create_intf_ep_files(struct usb_interface *intf,
 		struct usb_device *udev)
 {
@@ -777,23 +814,21 @@
 
 int usb_create_sysfs_intf_files(struct usb_interface *intf)
 {
-	struct device *dev = &intf->dev;
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_host_interface *alt = intf->cur_altsetting;
 	int retval;
 
 	if (intf->sysfs_files_created)
 		return 0;
-	retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
-	if (retval)
-		return retval;
 
+	/* The interface string may be present in some altsettings
+	 * and missing in others.  Hence its attribute cannot be created
+	 * before the uevent is broadcast.
+	 */
 	if (alt->string == NULL)
 		alt->string = usb_cache_string(udev, alt->desc.iInterface);
 	if (alt->string)
-		retval = device_create_file(dev, &dev_attr_interface);
-	if (intf->intf_assoc)
-		retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
+		retval = device_create_file(&intf->dev, &dev_attr_interface);
 	usb_create_intf_ep_files(intf, udev);
 	intf->sysfs_files_created = 1;
 	return 0;
@@ -807,7 +842,5 @@
 		return;
 	usb_remove_intf_ep_files(intf);
 	device_remove_file(dev, &dev_attr_interface);
-	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
-	sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
 	intf->sysfs_files_created = 0;
 }
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 1f0db51..3257743 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -291,6 +291,7 @@
 	device_initialize(&dev->dev);
 	dev->dev.bus = &usb_bus_type;
 	dev->dev.type = &usb_device_type;
+	dev->dev.groups = usb_device_groups;
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 1bf8ccb..1a8bc21 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -130,6 +130,10 @@
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 
+/* sysfs stuff */
+extern struct attribute_group *usb_device_groups[];
+extern struct attribute_group *usb_interface_groups[];
+
 /* usbfs stuff */
 extern struct mutex usbfs_mutex;
 extern struct usb_driver usbfs_driver;
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index ce337cb..f261d2a 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -3251,7 +3251,7 @@
 	/* pci setup */
 	if (pci_enable_device(pdev) < 0) {
 		kfree(dev);
-		dev = 0;
+		dev = NULL;
 		retval = -ENODEV;
 		goto finished;
 	}
@@ -3264,7 +3264,7 @@
 	if (!request_mem_region(resource, len, name)) {
 		dev_dbg(&pdev->dev, "pci device used already\n");
 		kfree(dev);
-		dev = 0;
+		dev = NULL;
 		retval = -EBUSY;
 		goto finished;
 	}
@@ -3274,7 +3274,7 @@
 	if (dev->virt_addr == NULL) {
 		dev_dbg(&pdev->dev, "start address cannot be mapped\n");
 		kfree(dev);
-		dev = 0;
+		dev = NULL;
 		retval = -EFAULT;
 		goto finished;
 	}
@@ -3282,7 +3282,7 @@
 	if (!pdev->irq) {
 		dev_err(&dev->pdev->dev, "irq not set\n");
 		kfree(dev);
-		dev = 0;
+		dev = NULL;
 		retval = -ENODEV;
 		goto finished;
 	}
@@ -3290,7 +3290,7 @@
 	if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
 		dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
 		kfree(dev);
-		dev = 0;
+		dev = NULL;
 		retval = -EBUSY;
 		goto finished;
 	}
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index e756023..07e5a0b 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -649,7 +649,13 @@
 
 	if (!ep->desc) {
 		spin_unlock_irqrestore(&udc->lock, flags);
-		DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+		/* REVISIT because this driver disables endpoints in
+		 * reset_all_endpoints() before calling disconnect(),
+		 * most gadget drivers would trigger this non-error ...
+		 */
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN)
+			DBG(DBG_ERR, "ep_disable: %s not enabled\n",
+					ep->ep.name);
 		return -EINVAL;
 	}
 	ep->desc = NULL;
@@ -1032,8 +1038,6 @@
 			.release	= nop_release,
 		},
 	},
-
-	.lock	= SPIN_LOCK_UNLOCKED,
 };
 
 /*
@@ -1052,6 +1056,12 @@
 		request_complete(ep, req, -ECONNRESET);
 	}
 
+	/* NOTE:  normally, the next call to the gadget driver is in
+	 * charge of disabling endpoints... usually disconnect().
+	 * The exception would be entering a high speed test mode.
+	 *
+	 * FIXME remove this code ... and retest thoroughly.
+	 */
 	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
 		if (ep->desc) {
 			spin_unlock(&udc->lock);
@@ -1219,7 +1229,7 @@
 static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
 		struct usb_ctrlrequest *crq)
 {
-	int retval = 0;;
+	int retval = 0;
 
 	switch (crq->bRequest) {
 	case USB_REQ_GET_STATUS: {
@@ -1693,6 +1703,14 @@
 		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
 		reset_all_endpoints(udc);
 
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver->disconnect) {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			spin_unlock(&udc->lock);
+			udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+
 		if (status & USBA_HIGH_SPEED) {
 			DBG(DBG_BUS, "High-speed bus reset detected\n");
 			udc->gadget.speed = USB_SPEED_HIGH;
@@ -1716,9 +1734,13 @@
 				| USBA_DET_SUSPEND
 				| USBA_END_OF_RESUME));
 
+		/*
+		 * Unclear why we hit this irregularly, e.g. in usbtest,
+		 * but it's clearly harmless...
+		 */
 		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
-			dev_warn(&udc->pdev->dev,
-				 "WARNING: EP0 configuration is invalid!\n");
+			dev_dbg(&udc->pdev->dev,
+				 "ODD: EP0 configuration is invalid!\n");
 	}
 
 	spin_unlock(&udc->lock);
@@ -1751,9 +1773,11 @@
 			reset_all_endpoints(udc);
 			toggle_bias(0);
 			usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-			spin_unlock(&udc->lock);
-			udc->driver->disconnect(&udc->gadget);
-			spin_lock(&udc->lock);
+			if (udc->driver->disconnect) {
+				spin_unlock(&udc->lock);
+				udc->driver->disconnect(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
 		}
 		udc->vbus_prev = vbus;
 	}
@@ -1825,7 +1849,7 @@
 
 	if (!udc->pdev)
 		return -ENODEV;
-	if (driver != udc->driver)
+	if (driver != udc->driver || !driver->unbind)
 		return -EINVAL;
 
 	if (udc->vbus_pin != -1)
@@ -1840,6 +1864,9 @@
 	toggle_bias(0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 
+	if (udc->driver->disconnect)
+		udc->driver->disconnect(&udc->gadget);
+
 	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
@@ -1879,6 +1906,7 @@
 		goto err_get_hclk;
 	}
 
+	spin_lock_init(&udc->lock);
 	udc->pdev = pdev;
 	udc->pclk = pclk;
 	udc->hclk = hclk;
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 75eba20..499b7a2 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1546,7 +1546,6 @@
 	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
 	dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
 	ep0_idle(dev);
-	strcpy(dev->dev->bus_id, "");
 
 	/* PXA endpoints init */
 	for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
@@ -1746,13 +1745,10 @@
 		ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
 	}
 
-	le16_to_cpus(&u.r.wValue);
-	le16_to_cpus(&u.r.wIndex);
-	le16_to_cpus(&u.r.wLength);
-
 	ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
 		u.r.bRequestType, u.r.bRequest,
-		u.r.wValue, u.r.wIndex, u.r.wLength);
+		le16_to_cpu(u.r.wValue), le16_to_cpu(u.r.wIndex),
+		le16_to_cpu(u.r.wLength));
 	if (unlikely(have_extrabytes))
 		goto stall;
 
@@ -2296,7 +2292,8 @@
 {
 	struct pxa_udc *udc = platform_get_drvdata(_dev);
 
-	udc_disable(udc);
+	if (udc_readl(udc, UDCCR) & UDCCR_UDE)
+		udc_disable(udc);
 }
 
 #ifdef CONFIG_PM
@@ -2361,9 +2358,8 @@
 	 * Upon exit from sleep mode and before clearing OTGPH,
 	 * Software must configure the USB OTG pad, UDC, and UHC
 	 * to the state they were in before entering sleep mode.
-	 *
-	 * Should be : PSSR |= PSSR_OTGPH;
 	 */
+	PSSR |= PSSR_OTGPH;
 
 	return 0;
 }
@@ -2387,6 +2383,9 @@
 
 static int __init udc_init(void)
 {
+	if (!cpu_is_pxa27x())
+		return -ENODEV;
+
 	printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
 	return platform_driver_probe(&udc_driver, pxa_udc_probe);
 }
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index 1d1b793..97453db 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -484,4 +484,12 @@
 #define ep_warn(ep, fmt, arg...) \
 	dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
 
+/*
+ * Cannot include pxa-regs.h, as register names are similar.
+ * So PSSR is redefined here. This should be removed once UDC registers will
+ * be gone from pxa-regs.h.
+ */
+#define PSSR		__REG(0x40F00004)	/* Power Manager Sleep Status */
+#define PSSR_OTGPH	(1 << 6)		/* OTG Peripheral Hold */
+
 #endif /* __LINUX_USB_GADGET_PXA27X_H */
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 54cdd6f..fa019fa 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -14,7 +14,6 @@
  * This software is distributed under the terms of the GNU General
  * Public License ("GPL") as published by the Free Software Foundation,
  * either version 2 of that License or (at your option) any later version.
- *
  */
 
 #include <linux/kernel.h>
@@ -33,7 +32,7 @@
 /* Defines */
 
 #define GS_VERSION_STR			"v2.2"
-#define GS_VERSION_NUM			0x0202
+#define GS_VERSION_NUM			0x2200
 
 #define GS_LONG_NAME			"Gadget Serial"
 #define GS_SHORT_NAME			"g_serial"
@@ -41,7 +40,11 @@
 #define GS_MAJOR			127
 #define GS_MINOR_START			0
 
-#define GS_NUM_PORTS			16
+/* REVISIT only one port is supported for now;
+ * see gs_{send,recv}_packet() ... no multiplexing,
+ * and no support for multiple ACM devices.
+ */
+#define GS_NUM_PORTS			1
 
 #define GS_NUM_CONFIGS			1
 #define GS_NO_CONFIG_ID			0
@@ -65,6 +68,9 @@
 
 #define GS_DEFAULT_USE_ACM		0
 
+/* 9600-8-N-1 ... matches init_termios.c_cflag and defaults
+ * expected by "usbser.sys" on MS-Windows.
+ */
 #define GS_DEFAULT_DTE_RATE		9600
 #define GS_DEFAULT_DATA_BITS		8
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
@@ -107,10 +113,6 @@
 #define GS_NOTIFY_MAXPACKET		8
 
 
-/* Structures */
-
-struct gs_dev;
-
 /* circular buffer */
 struct gs_buf {
 	unsigned int		buf_size;
@@ -119,12 +121,6 @@
 	char			*buf_put;
 };
 
-/* list of requests */
-struct gs_req_entry {
-	struct list_head	re_entry;
-	struct usb_request	*re_req;
-};
-
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
 	struct gs_dev		*port_dev;	/* pointer to device struct */
@@ -164,26 +160,7 @@
 
 /* Functions */
 
-/* module */
-static int __init gs_module_init(void);
-static void __exit gs_module_exit(void);
-
-/* tty driver */
-static int gs_open(struct tty_struct *tty, struct file *file);
-static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty,
-	const unsigned char *buf, int count);
-static int gs_put_char(struct tty_struct *tty, unsigned char ch);
-static void gs_flush_chars(struct tty_struct *tty);
-static int gs_write_room(struct tty_struct *tty);
-static int gs_chars_in_buffer(struct tty_struct *tty);
-static void gs_throttle(struct tty_struct * tty);
-static void gs_unthrottle(struct tty_struct * tty);
-static void gs_break(struct tty_struct *tty, int break_state);
-static int  gs_ioctl(struct tty_struct *tty, struct file *file,
-	unsigned int cmd, unsigned long arg);
-static void gs_set_termios(struct tty_struct *tty, struct ktermios *old);
-
+/* tty driver internals */
 static int gs_send(struct gs_dev *dev);
 static int gs_send_packet(struct gs_dev *dev, char *packet,
 	unsigned int size);
@@ -192,19 +169,7 @@
 static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);
 static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);
 
-/* gadget driver */
-static int gs_bind(struct usb_gadget *gadget);
-static void gs_unbind(struct usb_gadget *gadget);
-static int gs_setup(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl);
-static int gs_setup_standard(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl);
-static int gs_setup_class(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl);
-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
-	struct usb_request *req);
-static void gs_disconnect(struct usb_gadget *gadget);
+/* gadget driver internals */
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
 static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
@@ -214,10 +179,6 @@
 	gfp_t kmalloc_flags);
 static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
 
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
-	gfp_t kmalloc_flags);
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
-
 static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);
 static void gs_free_ports(struct gs_dev *dev);
 
@@ -232,62 +193,15 @@
 static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
 	unsigned int count);
 
-/* external functions */
-extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);
-
 
 /* Globals */
 
 static struct gs_dev *gs_device;
 
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_NOTIFY_NAME;
-
 static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
-static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
-static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
 
-static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
-
-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
-
-
-/* tty driver struct */
-static const struct tty_operations gs_tty_ops = {
-	.open =			gs_open,
-	.close =		gs_close,
-	.write =		gs_write,
-	.put_char =		gs_put_char,
-	.flush_chars =		gs_flush_chars,
-	.write_room =		gs_write_room,
-	.ioctl =		gs_ioctl,
-	.set_termios =		gs_set_termios,
-	.throttle =		gs_throttle,
-	.unthrottle =		gs_unthrottle,
-	.break_ctl =		gs_break,
-	.chars_in_buffer =	gs_chars_in_buffer,
-};
-static struct tty_driver *gs_tty_driver;
-
-/* gadget driver struct */
-static struct usb_gadget_driver gs_gadget_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed =		USB_SPEED_HIGH,
-#else
-	.speed =		USB_SPEED_FULL,
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-	.function =		GS_LONG_NAME,
-	.bind =			gs_bind,
-	.unbind =		gs_unbind,
-	.setup =		gs_setup,
-	.disconnect =		gs_disconnect,
-	.driver = {
-		.name =		GS_SHORT_NAME,
-	},
-};
-
+/*-------------------------------------------------------------------------*/
 
 /* USB descriptors */
 
@@ -304,7 +218,6 @@
 static struct usb_string gs_strings[] = {
 	{ GS_MANUFACTURER_STR_ID, manufacturer },
 	{ GS_PRODUCT_STR_ID, GS_LONG_NAME },
-	{ GS_SERIAL_STR_ID, "0" },
 	{ GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
 	{ GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
 	{ GS_CONTROL_STR_ID, "Gadget Serial Control" },
@@ -327,7 +240,6 @@
 	.idProduct =		__constant_cpu_to_le16(GS_PRODUCT_ID),
 	.iManufacturer =	GS_MANUFACTURER_STR_ID,
 	.iProduct =		GS_PRODUCT_STR_ID,
-	.iSerialNumber =	GS_SERIAL_STR_ID,
 	.bNumConfigurations =	GS_NUM_CONFIGS,
 };
 
@@ -364,7 +276,7 @@
 	.bDescriptorType =	USB_DT_INTERFACE,
 	.bInterfaceNumber =	GS_BULK_INTERFACE_ID,
 	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
 	.bInterfaceSubClass =	0,
 	.bInterfaceProtocol =	0,
 	.iInterface =		GS_DATA_STR_ID,
@@ -521,6 +433,8 @@
 };
 
 
+/*-------------------------------------------------------------------------*/
+
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
@@ -531,84 +445,23 @@
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
 
+static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 module_param(read_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
 
+static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
 module_param(write_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
 
+static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
 module_param(write_buf_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
 
+static unsigned int use_acm = GS_DEFAULT_USE_ACM;
 module_param(use_acm, uint, S_IRUGO);
 MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
 
-module_init(gs_module_init);
-module_exit(gs_module_exit);
-
-/*
-*  gs_module_init
-*
-*  Register as a USB gadget driver and a tty driver.
-*/
-static int __init gs_module_init(void)
-{
-	int i;
-	int retval;
-
-	retval = usb_gadget_register_driver(&gs_gadget_driver);
-	if (retval) {
-		pr_err("gs_module_init: cannot register gadget driver, "
-			"ret=%d\n", retval);
-		return retval;
-	}
-
-	gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
-	if (!gs_tty_driver)
-		return -ENOMEM;
-	gs_tty_driver->owner = THIS_MODULE;
-	gs_tty_driver->driver_name = GS_SHORT_NAME;
-	gs_tty_driver->name = "ttygs";
-	gs_tty_driver->major = GS_MAJOR;
-	gs_tty_driver->minor_start = GS_MINOR_START;
-	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-	gs_tty_driver->init_termios = tty_std_termios;
-	gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	tty_set_operations(gs_tty_driver, &gs_tty_ops);
-
-	for (i=0; i < GS_NUM_PORTS; i++)
-		mutex_init(&gs_open_close_lock[i]);
-
-	retval = tty_register_driver(gs_tty_driver);
-	if (retval) {
-		usb_gadget_unregister_driver(&gs_gadget_driver);
-		put_tty_driver(gs_tty_driver);
-		pr_err("gs_module_init: cannot register tty driver, "
-				"ret=%d\n", retval);
-		return retval;
-	}
-
-	pr_info("gs_module_init: %s %s loaded\n",
-			GS_LONG_NAME, GS_VERSION_STR);
-	return 0;
-}
-
-/*
-* gs_module_exit
-*
-* Unregister as a tty driver and a USB gadget driver.
-*/
-static void __exit gs_module_exit(void)
-{
-	tty_unregister_driver(gs_tty_driver);
-	put_tty_driver(gs_tty_driver);
-	usb_gadget_unregister_driver(&gs_gadget_driver);
-
-	pr_info("gs_module_exit: %s %s unloaded\n",
-			GS_LONG_NAME, GS_VERSION_STR);
-}
+/*-------------------------------------------------------------------------*/
 
 /* TTY Driver */
 
@@ -753,15 +606,15 @@
  * gs_close
  */
 
-#define GS_WRITE_FINISHED_EVENT_SAFELY(p)			\
-({								\
-	int cond;						\
-								\
-	spin_lock_irq(&(p)->port_lock);				\
-	cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \
-	spin_unlock_irq(&(p)->port_lock);			\
-	cond;							\
-})
+static int gs_write_finished_event_safely(struct gs_port *p)
+{
+	int cond;
+
+	spin_lock_irq(&(p)->port_lock);
+	cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf);
+	spin_unlock_irq(&(p)->port_lock);
+	return cond;
+}
 
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
@@ -807,7 +660,7 @@
 	if (gs_buf_data_avail(port->port_write_buf) > 0) {
 		spin_unlock_irq(&port->port_lock);
 		wait_event_interruptible_timeout(port->port_write_wait,
-					GS_WRITE_FINISHED_EVENT_SAFELY(port),
+					gs_write_finished_event_safely(port),
 					GS_CLOSE_TIMEOUT * HZ);
 		spin_lock_irq(&port->port_lock);
 	}
@@ -1065,6 +918,23 @@
 {
 }
 
+static const struct tty_operations gs_tty_ops = {
+	.open =			gs_open,
+	.close =		gs_close,
+	.write =		gs_write,
+	.put_char =		gs_put_char,
+	.flush_chars =		gs_flush_chars,
+	.write_room =		gs_write_room,
+	.ioctl =		gs_ioctl,
+	.set_termios =		gs_set_termios,
+	.throttle =		gs_throttle,
+	.unthrottle =		gs_unthrottle,
+	.break_ctl =		gs_break,
+	.chars_in_buffer =	gs_chars_in_buffer,
+};
+
+/*-------------------------------------------------------------------------*/
+
 /*
 * gs_send
 *
@@ -1080,7 +950,6 @@
 	unsigned long flags;
 	struct usb_ep *ep;
 	struct usb_request *req;
-	struct gs_req_entry *req_entry;
 
 	if (dev == NULL) {
 		pr_err("gs_send: NULL device pointer\n");
@@ -1093,10 +962,8 @@
 
 	while(!list_empty(&dev->dev_req_list)) {
 
-		req_entry = list_entry(dev->dev_req_list.next,
-			struct gs_req_entry, re_entry);
-
-		req = req_entry->re_req;
+		req = list_entry(dev->dev_req_list.next,
+				struct usb_request, list);
 
 		len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
@@ -1106,7 +973,7 @@
 					*((unsigned char *)req->buf),
 					*((unsigned char *)req->buf+1),
 					*((unsigned char *)req->buf+2));
-			list_del(&req_entry->re_entry);
+			list_del(&req->list);
 			req->length = len;
 			spin_unlock_irqrestore(&dev->dev_lock, flags);
 			if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
@@ -1289,7 +1156,6 @@
 static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct gs_dev *dev = ep->driver_data;
-	struct gs_req_entry *gs_req = req->context;
 
 	if (dev == NULL) {
 		pr_err("gs_write_complete: NULL device pointer\n");
@@ -1300,13 +1166,8 @@
 	case 0:
 		/* normal completion */
 requeue:
-		if (gs_req == NULL) {
-			pr_err("gs_write_complete: NULL request pointer\n");
-			return;
-		}
-
 		spin_lock(&dev->dev_lock);
-		list_add(&gs_req->re_entry, &dev->dev_req_list);
+		list_add(&req->list, &dev->dev_req_list);
 		spin_unlock(&dev->dev_lock);
 
 		gs_send(dev);
@@ -1328,9 +1189,39 @@
 	}
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* Gadget Driver */
 
 /*
+ * gs_unbind
+ *
+ * Called on module unload.  Frees the control request and device
+ * structure.
+ */
+static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
+{
+	struct gs_dev *dev = get_gadget_data(gadget);
+
+	gs_device = NULL;
+
+	/* read/write requests already freed, only control request remains */
+	if (dev != NULL) {
+		if (dev->dev_ctrl_req != NULL) {
+			gs_free_req(gadget->ep0, dev->dev_ctrl_req);
+			dev->dev_ctrl_req = NULL;
+		}
+		gs_reset_config(dev);
+		gs_free_ports(dev);
+		kfree(dev);
+		set_gadget_data(gadget, NULL);
+	}
+
+	pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+		GS_VERSION_STR);
+}
+
+/*
  * gs_bind
  *
  * Called on module load.  Allocates and initializes the device
@@ -1362,19 +1253,23 @@
 			__constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
 	}
 
+	dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+
 	usb_ep_autoconfig_reset(gadget);
 
 	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
 	if (!ep)
 		goto autoconf_fail;
-	EP_IN_NAME = ep->name;
-	ep->driver_data = ep;	/* claim the endpoint */
+	dev->dev_in_ep = ep;
+	ep->driver_data = dev;	/* claim the endpoint */
 
 	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
 	if (!ep)
 		goto autoconf_fail;
-	EP_OUT_NAME = ep->name;
-	ep->driver_data = ep;	/* claim the endpoint */
+	dev->dev_out_ep = ep;
+	ep->driver_data = dev;	/* claim the endpoint */
 
 	if (use_acm) {
 		ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
@@ -1384,8 +1279,8 @@
 		}
 		gs_device_desc.idProduct = __constant_cpu_to_le16(
 						GS_CDC_PRODUCT_ID),
-		EP_NOTIFY_NAME = ep->name;
-		ep->driver_data = ep;	/* claim the endpoint */
+		dev->dev_notify_ep = ep;
+		ep->driver_data = dev;	/* claim the endpoint */
 	}
 
 	gs_device_desc.bDeviceClass = use_acm
@@ -1415,9 +1310,7 @@
 		gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 
-	gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
-	if (dev == NULL)
-		return -ENOMEM;
+	gs_device = dev;
 
 	snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
 		init_utsname()->sysname, init_utsname()->release,
@@ -1441,8 +1334,6 @@
 		gs_unbind(gadget);
 		return -ENOMEM;
 	}
-	dev->dev_ctrl_req->complete = gs_setup_complete;
-
 	gadget->ep0->driver_data = dev;
 
 	pr_info("gs_bind: %s %s bound\n",
@@ -1451,99 +1342,11 @@
 	return 0;
 
 autoconf_fail:
+	kfree(dev);
 	pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
 	return -ENODEV;
 }
 
-/*
- * gs_unbind
- *
- * Called on module unload.  Frees the control request and device
- * structure.
- */
-static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
-{
-	struct gs_dev *dev = get_gadget_data(gadget);
-
-	gs_device = NULL;
-
-	/* read/write requests already freed, only control request remains */
-	if (dev != NULL) {
-		if (dev->dev_ctrl_req != NULL) {
-			gs_free_req(gadget->ep0, dev->dev_ctrl_req);
-			dev->dev_ctrl_req = NULL;
-		}
-		gs_free_ports(dev);
-		if (dev->dev_notify_ep)
-			usb_ep_disable(dev->dev_notify_ep);
-		if (dev->dev_in_ep)
-			usb_ep_disable(dev->dev_in_ep);
-		if (dev->dev_out_ep)
-			usb_ep_disable(dev->dev_out_ep);
-		kfree(dev);
-		set_gadget_data(gadget, NULL);
-	}
-
-	pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
-		GS_VERSION_STR);
-}
-
-/*
- * gs_setup
- *
- * Implements all the control endpoint functionality that's not
- * handled in hardware or the hardware driver.
- *
- * Returns the size of the data sent to the host, or a negative
- * error number.
- */
-static int gs_setup(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl)
-{
-	int ret = -EOPNOTSUPP;
-	struct gs_dev *dev = get_gadget_data(gadget);
-	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = le16_to_cpu(ctrl->wIndex);
-	u16 wValue = le16_to_cpu(ctrl->wValue);
-	u16 wLength = le16_to_cpu(ctrl->wLength);
-
-	req->complete = gs_setup_complete;
-
-	switch (ctrl->bRequestType & USB_TYPE_MASK) {
-	case USB_TYPE_STANDARD:
-		ret = gs_setup_standard(gadget,ctrl);
-		break;
-
-	case USB_TYPE_CLASS:
-		ret = gs_setup_class(gadget,ctrl);
-		break;
-
-	default:
-		pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
-			"value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest,
-			wValue, wIndex, wLength);
-		break;
-	}
-
-	/* respond with data transfer before status phase? */
-	if (ret >= 0) {
-		req->length = ret;
-		req->zero = ret < wLength
-				&& (ret % gadget->ep0->maxpacket) == 0;
-		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-		if (ret < 0) {
-			pr_err("gs_setup: cannot queue response, ret=%d\n",
-				ret);
-			req->status = 0;
-			gs_setup_complete(gadget->ep0, req);
-		}
-	}
-
-	/* device either stalls (ret < 0) or reports success */
-	return ret;
-}
-
 static int gs_setup_standard(struct usb_gadget *gadget,
 	const struct usb_ctrlrequest *ctrl)
 {
@@ -1673,6 +1476,42 @@
 	return ret;
 }
 
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+		struct usb_request *req)
+{
+	struct gs_dev *dev = ep->driver_data;
+	struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+	switch (req->status) {
+	case 0:
+		/* normal completion */
+		if (req->actual != sizeof(port->port_line_coding))
+			usb_ep_set_halt(ep);
+		else if (port) {
+			struct usb_cdc_line_coding	*value = req->buf;
+
+			/* REVISIT:  we currently just remember this data.
+			 * If we change that, (a) validate it first, then
+			 * (b) update whatever hardware needs updating.
+			 */
+			spin_lock(&port->port_lock);
+			port->port_line_coding = *value;
+			spin_unlock(&port->port_lock);
+		}
+		break;
+
+	case -ESHUTDOWN:
+		/* disconnect */
+		gs_free_req(ep, req);
+		break;
+
+	default:
+		/* unexpected */
+		break;
+	}
+	return;
+}
+
 static int gs_setup_class(struct usb_gadget *gadget,
 	const struct usb_ctrlrequest *ctrl)
 {
@@ -1734,42 +1573,6 @@
 	return ret;
 }
 
-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
-		struct usb_request *req)
-{
-	struct gs_dev *dev = ep->driver_data;
-	struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
-
-	switch (req->status) {
-	case 0:
-		/* normal completion */
-		if (req->actual != sizeof(port->port_line_coding))
-			usb_ep_set_halt(ep);
-		else if (port) {
-			struct usb_cdc_line_coding	*value = req->buf;
-
-			/* REVISIT:  we currently just remember this data.
-			 * If we change that, (a) validate it first, then
-			 * (b) update whatever hardware needs updating.
-			 */
-			spin_lock(&port->port_lock);
-			port->port_line_coding = *value;
-			spin_unlock(&port->port_lock);
-		}
-		break;
-
-	case -ESHUTDOWN:
-		/* disconnect */
-		gs_free_req(ep, req);
-		break;
-
-	default:
-		/* unexpected */
-		break;
-	}
-	return;
-}
-
 /*
  * gs_setup_complete
  */
@@ -1783,6 +1586,62 @@
 }
 
 /*
+ * gs_setup
+ *
+ * Implements all the control endpoint functionality that's not
+ * handled in hardware or the hardware driver.
+ *
+ * Returns the size of the data sent to the host, or a negative
+ * error number.
+ */
+static int gs_setup(struct usb_gadget *gadget,
+	const struct usb_ctrlrequest *ctrl)
+{
+	int		ret = -EOPNOTSUPP;
+	struct gs_dev	*dev = get_gadget_data(gadget);
+	struct usb_request *req = dev->dev_ctrl_req;
+	u16		wIndex = le16_to_cpu(ctrl->wIndex);
+	u16		wValue = le16_to_cpu(ctrl->wValue);
+	u16		wLength = le16_to_cpu(ctrl->wLength);
+
+	req->complete = gs_setup_complete;
+
+	switch (ctrl->bRequestType & USB_TYPE_MASK) {
+	case USB_TYPE_STANDARD:
+		ret = gs_setup_standard(gadget, ctrl);
+		break;
+
+	case USB_TYPE_CLASS:
+		ret = gs_setup_class(gadget, ctrl);
+		break;
+
+	default:
+		pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+			"value=%04x, index=%04x, length=%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			wValue, wIndex, wLength);
+		break;
+	}
+
+	/* respond with data transfer before status phase? */
+	if (ret >= 0) {
+		req->length = ret;
+		req->zero = ret < wLength
+				&& (ret % gadget->ep0->maxpacket) == 0;
+		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+		if (ret < 0) {
+			pr_err("gs_setup: cannot queue response, ret=%d\n",
+				ret);
+			req->status = 0;
+			gs_setup_complete(gadget->ep0, req);
+		}
+	}
+
+	/* device either stalls (ret < 0) or reports success */
+	return ret;
+}
+
+/*
  * gs_disconnect
  *
  * Called when the device is disconnected.  Frees the closed
@@ -1811,6 +1670,23 @@
 	pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
 }
 
+static struct usb_gadget_driver gs_gadget_driver = {
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+	.speed =		USB_SPEED_HIGH,
+#else
+	.speed =		USB_SPEED_FULL,
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
+	.function =		GS_LONG_NAME,
+	.bind =			gs_bind,
+	.unbind =		gs_unbind,
+	.setup =		gs_setup,
+	.disconnect =		gs_disconnect,
+	.driver = {
+		.name =		GS_SHORT_NAME,
+		.owner =	THIS_MODULE,
+	},
+};
+
 /*
  * gs_set_config
  *
@@ -1826,9 +1702,8 @@
 	int ret = 0;
 	struct usb_gadget *gadget = dev->dev_gadget;
 	struct usb_ep *ep;
-	struct usb_endpoint_descriptor *ep_desc;
+	struct usb_endpoint_descriptor *out, *in, *notify;
 	struct usb_request *req;
-	struct gs_req_entry *req_entry;
 
 	if (dev == NULL) {
 		pr_err("gs_set_config: NULL device pointer\n");
@@ -1846,86 +1721,62 @@
 	case GS_BULK_CONFIG_ID:
 		if (use_acm)
 			return -EINVAL;
-		/* device specific optimizations */
-		if (gadget_is_net2280(gadget))
-			net2280_set_fifo_mode(gadget, 1);
 		break;
 	case GS_ACM_CONFIG_ID:
 		if (!use_acm)
 			return -EINVAL;
-		/* device specific optimizations */
-		if (gadget_is_net2280(gadget))
-			net2280_set_fifo_mode(gadget, 1);
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	dev->dev_config = config;
-
-	gadget_for_each_ep(ep, gadget) {
-
-		if (EP_NOTIFY_NAME
-		&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-			ep_desc = choose_ep_desc(gadget,
+	in = choose_ep_desc(gadget,
+			&gs_highspeed_in_desc,
+			&gs_fullspeed_in_desc);
+	out = choose_ep_desc(gadget,
+			&gs_highspeed_out_desc,
+			&gs_fullspeed_out_desc);
+	notify = dev->dev_notify_ep
+		? choose_ep_desc(gadget,
 				&gs_highspeed_notify_desc,
-				&gs_fullspeed_notify_desc);
-			ret = usb_ep_enable(ep,ep_desc);
-			if (ret == 0) {
-				ep->driver_data = dev;
-				dev->dev_notify_ep = ep;
-				dev->dev_notify_ep_desc = ep_desc;
-			} else {
-				pr_err("gs_set_config: cannot enable NOTIFY "
-					"endpoint %s, ret=%d\n",
-					ep->name, ret);
-				goto exit_reset_config;
-			}
-		}
+				&gs_fullspeed_notify_desc)
+		: NULL;
 
-		else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-			ep_desc = choose_ep_desc(gadget,
-				&gs_highspeed_in_desc,
-				&gs_fullspeed_in_desc);
-			ret = usb_ep_enable(ep,ep_desc);
-			if (ret == 0) {
-				ep->driver_data = dev;
-				dev->dev_in_ep = ep;
-				dev->dev_in_ep_desc = ep_desc;
-			} else {
-				pr_err("gs_set_config: cannot enable IN "
-					"endpoint %s, ret=%d\n",
-					ep->name, ret);
-				goto exit_reset_config;
-			}
-		}
-
-		else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-			ep_desc = choose_ep_desc(gadget,
-				&gs_highspeed_out_desc,
-				&gs_fullspeed_out_desc);
-			ret = usb_ep_enable(ep,ep_desc);
-			if (ret == 0) {
-				ep->driver_data = dev;
-				dev->dev_out_ep = ep;
-				dev->dev_out_ep_desc = ep_desc;
-			} else {
-				pr_err("gs_set_config: cannot enable OUT "
-					"endpoint %s, ret=%d\n",
-					ep->name, ret);
-				goto exit_reset_config;
-			}
-		}
-
+	ret = usb_ep_enable(dev->dev_in_ep, in);
+	if (ret == 0) {
+		dev->dev_in_ep_desc = in;
+	} else {
+		pr_debug("%s: cannot enable %s %s, ret=%d\n",
+			__func__, "IN", dev->dev_in_ep->name, ret);
+		return ret;
 	}
 
-	if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
-	|| (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
-		pr_err("gs_set_config: cannot find endpoints\n");
-		ret = -ENODEV;
-		goto exit_reset_config;
+	ret = usb_ep_enable(dev->dev_out_ep, out);
+	if (ret == 0) {
+		dev->dev_out_ep_desc = out;
+	} else {
+		pr_debug("%s: cannot enable %s %s, ret=%d\n",
+			__func__, "OUT", dev->dev_out_ep->name, ret);
+fail0:
+		usb_ep_disable(dev->dev_in_ep);
+		return ret;
 	}
 
+	if (notify) {
+		ret = usb_ep_enable(dev->dev_notify_ep, notify);
+		if (ret == 0) {
+			dev->dev_notify_ep_desc = notify;
+		} else {
+			pr_debug("%s: cannot enable %s %s, ret=%d\n",
+				__func__, "NOTIFY",
+				dev->dev_notify_ep->name, ret);
+			usb_ep_disable(dev->dev_out_ep);
+			goto fail0;
+		}
+	}
+
+	dev->dev_config = config;
+
 	/* allocate and queue read requests */
 	ep = dev->dev_out_ep;
 	for (i=0; i<read_q_size && ret == 0; i++) {
@@ -1946,9 +1797,10 @@
 	/* allocate write requests, and put on free list */
 	ep = dev->dev_in_ep;
 	for (i=0; i<write_q_size; i++) {
-		if ((req_entry=gs_alloc_req_entry(ep, ep->maxpacket, GFP_ATOMIC))) {
-			req_entry->re_req->complete = gs_write_complete;
-			list_add(&req_entry->re_entry, &dev->dev_req_list);
+		req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+		if (req) {
+			req->complete = gs_write_complete;
+			list_add(&req->list, &dev->dev_req_list);
 		} else {
 			pr_err("gs_set_config: cannot allocate "
 					"write requests\n");
@@ -1986,7 +1838,7 @@
  */
 static void gs_reset_config(struct gs_dev *dev)
 {
-	struct gs_req_entry *req_entry;
+	struct usb_request *req;
 
 	if (dev == NULL) {
 		pr_err("gs_reset_config: NULL device pointer\n");
@@ -2000,26 +1852,18 @@
 
 	/* free write requests on the free list */
 	while(!list_empty(&dev->dev_req_list)) {
-		req_entry = list_entry(dev->dev_req_list.next,
-			struct gs_req_entry, re_entry);
-		list_del(&req_entry->re_entry);
-		gs_free_req_entry(dev->dev_in_ep, req_entry);
+		req = list_entry(dev->dev_req_list.next,
+				struct usb_request, list);
+		list_del(&req->list);
+		gs_free_req(dev->dev_in_ep, req);
 	}
 
 	/* disable endpoints, forcing completion of pending i/o; */
 	/* completion handlers free their requests in this case */
-	if (dev->dev_notify_ep) {
+	if (dev->dev_notify_ep)
 		usb_ep_disable(dev->dev_notify_ep);
-		dev->dev_notify_ep = NULL;
-	}
-	if (dev->dev_in_ep) {
-		usb_ep_disable(dev->dev_in_ep);
-		dev->dev_in_ep = NULL;
-	}
-	if (dev->dev_out_ep) {
-		usb_ep_disable(dev->dev_out_ep);
-		dev->dev_out_ep = NULL;
-	}
+	usb_ep_disable(dev->dev_in_ep);
+	usb_ep_disable(dev->dev_out_ep);
 }
 
 /*
@@ -2113,46 +1957,6 @@
 }
 
 /*
- * gs_alloc_req_entry
- *
- * Allocates a request and its buffer, using the given
- * endpoint, buffer len, and kmalloc flags.
- */
-static struct gs_req_entry *
-gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
-{
-	struct gs_req_entry	*req;
-
-	req = kmalloc(sizeof(struct gs_req_entry), kmalloc_flags);
-	if (req == NULL)
-		return NULL;
-
-	req->re_req = gs_alloc_req(ep, len, kmalloc_flags);
-	if (req->re_req == NULL) {
-		kfree(req);
-		return NULL;
-	}
-
-	req->re_req->context = req;
-
-	return req;
-}
-
-/*
- * gs_free_req_entry
- *
- * Frees a request and its buffer.
- */
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
-{
-	if (ep != NULL && req != NULL) {
-		if (req->re_req != NULL)
-			gs_free_req(ep, req->re_req);
-		kfree(req);
-	}
-}
-
-/*
  * gs_alloc_ports
  *
  * Allocate all ports and set the gs_dev struct to point to them.
@@ -2233,6 +2037,8 @@
 	}
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* Circular Buffer */
 
 /*
@@ -2393,3 +2199,77 @@
 
 	return count;
 }
+
+/*-------------------------------------------------------------------------*/
+
+static struct tty_driver *gs_tty_driver;
+
+/*
+ *  gs_module_init
+ *
+ *  Register as a USB gadget driver and a tty driver.
+ */
+static int __init gs_module_init(void)
+{
+	int i;
+	int retval;
+
+	retval = usb_gadget_register_driver(&gs_gadget_driver);
+	if (retval) {
+		pr_err("gs_module_init: cannot register gadget driver, "
+			"ret=%d\n", retval);
+		return retval;
+	}
+
+	gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
+	if (!gs_tty_driver)
+		return -ENOMEM;
+	gs_tty_driver->owner = THIS_MODULE;
+	gs_tty_driver->driver_name = GS_SHORT_NAME;
+	gs_tty_driver->name = "ttygs";
+	gs_tty_driver->major = GS_MAJOR;
+	gs_tty_driver->minor_start = GS_MINOR_START;
+	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	gs_tty_driver->init_termios = tty_std_termios;
+	/* must match GS_DEFAULT_DTE_RATE and friends */
+	gs_tty_driver->init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	gs_tty_driver->init_termios.c_ispeed = GS_DEFAULT_DTE_RATE;
+	gs_tty_driver->init_termios.c_ospeed = GS_DEFAULT_DTE_RATE;
+	tty_set_operations(gs_tty_driver, &gs_tty_ops);
+
+	for (i = 0; i < GS_NUM_PORTS; i++)
+		mutex_init(&gs_open_close_lock[i]);
+
+	retval = tty_register_driver(gs_tty_driver);
+	if (retval) {
+		usb_gadget_unregister_driver(&gs_gadget_driver);
+		put_tty_driver(gs_tty_driver);
+		pr_err("gs_module_init: cannot register tty driver, "
+				"ret=%d\n", retval);
+		return retval;
+	}
+
+	pr_info("gs_module_init: %s %s loaded\n",
+			GS_LONG_NAME, GS_VERSION_STR);
+	return 0;
+}
+module_init(gs_module_init);
+
+/*
+ * gs_module_exit
+ *
+ * Unregister as a tty driver and a USB gadget driver.
+ */
+static void __exit gs_module_exit(void)
+{
+	tty_unregister_driver(gs_tty_driver);
+	put_tty_driver(gs_tty_driver);
+	usb_gadget_unregister_driver(&gs_gadget_driver);
+
+	pr_info("gs_module_exit: %s %s unloaded\n",
+			GS_LONG_NAME, GS_VERSION_STR);
+}
+module_exit(gs_module_exit);
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 4ba96c1..c9cec87 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -988,7 +988,7 @@
 			 * This did not trigger for a long time now.
 			 */
 			printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
-					"%d of %d done: %08x cur: %08x\n", qtd,
+					"%d of %zu done: %08x cur: %08x\n", qtd,
 					urb, qh, PTD_XFERRED_LENGTH(dw3),
 					qtd->length, done_map,
 					(1 << queue_entry));
@@ -1088,7 +1088,7 @@
 		} else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
 			/* short BULK received */
 
-			printk(KERN_ERR "short bulk, %d instead %d\n", length,
+			printk(KERN_ERR "short bulk, %d instead %zu\n", length,
 					qtd->length);
 			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
 				urb->status = -EREMOTEIO;
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 73fb2a3..440bf94 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -256,7 +256,7 @@
 
 static int __init isp1760_init(void)
 {
-	int ret;
+	int ret = -ENODEV;
 
 	init_kmem_once();
 
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 77204f0..e899a77 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -90,7 +90,7 @@
 	struct device *dev = &pdev->dev;
 	struct resource	*res, *mem;
 	int retval, irq;
-	struct usb_hcd *hcd = 0;
+	struct usb_hcd *hcd = NULL;
 
 	irq = retval = platform_get_irq(pdev, 0);
 	if (retval < 0)
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 7aafd53..189a9db 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -63,9 +63,6 @@
 #define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
 #define USB_DEVICE_ID_VERNIER_LCSPEC	0x0006
 
-#define USB_VENDOR_ID_MICROCHIP		0x04d8
-#define USB_DEVICE_ID_PICDEM		0x000c
-
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 #define USB_LD_MINOR_BASE	0
 #else
@@ -92,7 +89,6 @@
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
-	{ USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
 	{ }					/* Terminating entry */
 };
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 742be3c..054dedd 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -856,6 +856,11 @@
 		struct urb		*u;
 		struct usb_ctrlrequest	req;
 		struct subcase		*reqp;
+
+		/* sign of this variable means:
+		 *  -: tested code must return this (negative) error code
+		 *  +: tested code may return this (negative too) error code
+		 */
 		int			expected = 0;
 
 		/* requests here are mostly expected to succeed on any
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 2cffec8..9ba64cc 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -447,6 +447,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mos7840.  If unsure, choose N.
 
+config USB_SERIAL_MOTOROLA
+	tristate "USB Motorola Phone modem driver"
+	---help---
+	  Say Y here if you want to use a Motorola phone with a USB
+	  connector as a modem link.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called moto_modem.  If unsure, choose N.
+
 config USB_SERIAL_NAVMAN
 	tristate "USB Navman GPS device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 7568595..17a762a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -39,6 +39,7 @@
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_MOS7720)		+= mos7720.o
 obj-$(CONFIG_USB_SERIAL_MOS7840)		+= mos7840.o
+obj-$(CONFIG_USB_SERIAL_MOTOROLA)		+= moto_modem.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
new file mode 100644
index 0000000..2e8e054
--- /dev/null
+++ b/drivers/usb/serial/moto_modem.c
@@ -0,0 +1,70 @@
+/*
+ * Motorola USB Phone driver
+ *
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ * {sigh}
+ * Mororola should be using the CDC ACM USB spec, but instead
+ * they try to just "do their own thing"...  This driver should handle a
+ * few phones in which a basic "dumb serial connection" is needed to be
+ * able to get a connection through to them.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x05c6, 0x3197) },	/* unknown Motorola phone */
+	{ USB_DEVICE(0x0c44, 0x0022) },	/* unknown Mororola phone */
+	{ USB_DEVICE(0x22b8, 0x2a64) },	/* Motorola KRZR K1m */
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver moto_driver = {
+	.name =		"moto-modem",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id = 	1,
+};
+
+static struct usb_serial_driver moto_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"moto-modem",
+	},
+	.id_table =		id_table,
+	.num_ports =		1,
+};
+
+static int __init moto_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&moto_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&moto_driver);
+	if (retval)
+		usb_serial_deregister(&moto_device);
+	return retval;
+}
+
+static void __exit moto_exit(void)
+{
+	usb_deregister(&moto_driver);
+	usb_serial_deregister(&moto_device);
+}
+
+module_init(moto_init);
+module_exit(moto_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e4be2d4..e7e016e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -154,8 +154,6 @@
 #define NOVATELWIRELESS_PRODUCT_MC727		0x4100
 #define NOVATELWIRELESS_PRODUCT_MC950D		0x4400
 
-#define NOVATELWIRELESS_PRODUCT_U727		0x5010
-
 /* FUTURE NOVATEL PRODUCTS */
 #define NOVATELWIRELESS_PRODUCT_EVDO_1		0x6000
 #define NOVATELWIRELESS_PRODUCT_HSPA_1		0x7000
@@ -184,6 +182,9 @@
 #define AXESSTEL_VENDOR_ID			0x1726
 #define AXESSTEL_PRODUCT_MV110H			0x1000
 
+#define ONDA_VENDOR_ID				0x19d2
+#define ONDA_PRODUCT_ET502HS			0x0002
+
 #define BANDRICH_VENDOR_ID			0x1A8D
 #define BANDRICH_PRODUCT_C100_1			0x1002
 #define BANDRICH_PRODUCT_C100_2			0x1003
@@ -269,7 +270,6 @@
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
-	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel U727 */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_1) }, /* Novatel EVDO product */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_1) }, /* Novatel HSPA product */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EMBEDDED_1) }, /* Novatel Embedded product */
@@ -293,14 +293,17 @@
 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8133) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */
 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8136) },	/* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) },	/* Dell Wireless HSDPA 5520 */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8138) },	/* Dell Wireless 5520 Voda I Mobile Broadband (3G HSDPA) Minicard */
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
 	{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
+	{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
 	{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
+	{ USB_DEVICE(0x19d2, 0x0001) }, 	/* Telstra NextG CDMA */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index a0ed889..1b09578 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -401,6 +401,14 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_CYP_ATACB, US_PR_BULK, NULL,
+		0),
+#endif
+
 /* Reported by Simon Levitt <simon@whattf.com>
  * This entry needs Sub and Proto fields */
 UNUSUAL_DEV(  0x04b8, 0x0601, 0x0100, 0x0100,
@@ -539,17 +547,6 @@
 		"CD-RW Device",
 		US_SC_8020, US_PR_CB, NULL, 0),
 
-/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
- * Device uses standards-violating 32-byte Bulk Command Block Wrappers and
- * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
- */
-
-UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x0100,
-		"Kobian Mercury",
-		"Binocam DCB-132",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_BULK32),
-
 #ifdef CONFIG_USB_STORAGE_USBAT
 UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
 		"Shuttle/SCM",
@@ -565,6 +562,16 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MAX_SECTORS_64),
 
+/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
+ * Device uses standards-violating 32-byte Bulk Command Block Wrappers and
+ * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
+ */
+UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x0100,
+		"Kobian Mercury",
+		"Binocam DCB-132",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_BULK32),
+
 /* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
 UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
 		"Belkin",
@@ -1304,6 +1311,16 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_DEVICE ),
 
+/* Reported by F. Aben <f.aben@option.com>
+ * This device (wrongly) has a vendor-specific device descriptor.
+ * The entry is needed so usb-storage can bind to it's mass-storage
+ * interface as an interface driver */
+UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
+		"Option",
+		"GI 0401 SD-Card",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		0 ),
+
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
 		"ATI",
@@ -1361,13 +1378,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY),
 
-/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
-UNUSUAL_DEV(  0x2770, 0x915d, 0x0010, 0x0010,
-		"INTOVA",
-		"Pixtreme",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
-
 /*
  * Entry for Jenoptik JD 5200z3
  *
@@ -1684,6 +1694,16 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Mauro Andreolini <andreoli@weblab.ing.unimo.it>
+ * This entry is needed to bypass the ZeroCD mechanism
+ * and to properly load as a modem device.
+ */
+UNUSUAL_DEV(  0x19d2, 0x2000, 0x0000, 0x0000,
+		"Onda ET502HS",
+		"USB MMC Storage",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE),
+
 /* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
  * and Renato Perini <rperini@email.it>
  */
@@ -1721,6 +1741,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_GO_SLOW ),
 
+/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
+UNUSUAL_DEV(  0x2770, 0x915d, 0x0010, 0x0010,
+		"INTOVA",
+		"Pixtreme",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
 /*
  * David Härdeman <david@2gen.com>
  * The key makes the SCSI stack print confusing (but harmless) messages
@@ -1745,14 +1772,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_CAPACITY_HEURISTICS),
 
-#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
-UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
-		"Cypress",
-		"Cypress AT2LP",
-		US_SC_CYP_ATACB, US_PR_BULK, NULL,
-		0),
-#endif
-
 /* Control/Bulk transport for all SubClass values */
 USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
 USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index bb1dada..2cdaf1f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -171,7 +171,6 @@
 config FB_DEFERRED_IO
 	bool
 	depends on FB
-	default y
 
 config FB_METRONOME
 	tristate
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8ffdf35..b004036 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -441,14 +441,15 @@
 
 	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
 
-	value = (value / 2) - 1;
-	dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n", value);
-
-	if (value <= 0) {
+	if (value < 2) {
 		dev_notice(info->device, "Bypassing pixel clock divider\n");
 		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
 	} else {
-		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+		value = (value / 2) - 1;
+		dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n",
+				value);
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+				value << ATMEL_LCDC_CLKVAL_OFFSET);
 		info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
 		dev_dbg(info->device, "  updated pixclk:     %lu KHz\n",
 					PICOS2KHZ(info->var.pixclock));
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index ad31983..5fa8b76 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1853,6 +1853,8 @@
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	struct display *p = &fb_display[vc->vc_num];
 	int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
+	unsigned short saved_ec;
+	int ret;
 
 	if (fbcon_is_inactive(vc, info))
 		return -EINVAL;
@@ -1865,6 +1867,11 @@
 	 *           whole screen (prevents flicker).
 	 */
 
+	saved_ec = vc->vc_video_erase_char;
+	vc->vc_video_erase_char = vc->vc_scrl_erase_char;
+
+	ret = 0;
+
 	switch (dir) {
 	case SM_UP:
 		if (count > vc->vc_rows)	/* Maximum realistic size */
@@ -1883,7 +1890,7 @@
 							(b - count)),
 				    vc->vc_scrl_erase_char,
 				    vc->vc_size_row * count);
-			return 1;
+			ret = 1;
 			break;
 
 		case SCROLL_WRAP_MOVE:
@@ -1955,7 +1962,8 @@
 							(b - count)),
 				    vc->vc_scrl_erase_char,
 				    vc->vc_size_row * count);
-			return 1;
+			ret = 1;
+			break;
 		}
 		break;
 
@@ -1974,7 +1982,7 @@
 							t),
 				    vc->vc_scrl_erase_char,
 				    vc->vc_size_row * count);
-			return 1;
+			ret = 1;
 			break;
 
 		case SCROLL_WRAP_MOVE:
@@ -2044,10 +2052,13 @@
 							t),
 				    vc->vc_scrl_erase_char,
 				    vc->vc_size_row * count);
-			return 1;
+			ret = 1;
+			break;
 		}
+		break;
 	}
-	return 0;
+	vc->vc_video_erase_char = saved_ec;
+	return ret;
 }
 
 
@@ -2507,6 +2518,9 @@
 			c = vc->vc_video_erase_char;
 			vc->vc_video_erase_char =
 			    ((c & 0xfe00) >> 1) | (c & 0xff);
+			c = vc->vc_def_color;
+			vc->vc_scrl_erase_char =
+			    ((c & 0xFE00) >> 1) | (c & 0xFF);
 			vc->vc_attr >>= 1;
 		}
 	} else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2537,9 +2551,14 @@
 			if (vc->vc_can_do_color) {
 				vc->vc_video_erase_char =
 				    ((c & 0xff00) << 1) | (c & 0xff);
+				c = vc->vc_def_color;
+				vc->vc_scrl_erase_char =
+				    ((c & 0xFF00) << 1) | (c & 0xFF);
 				vc->vc_attr <<= 1;
-			} else
+			} else {
 				vc->vc_video_erase_char = c & ~0x100;
+				vc->vc_scrl_erase_char = c & ~0x100;
+			}
 		}
 
 	}
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
index 685761a..4db6b48 100644
--- a/drivers/video/pnx4008/pnxrgbfb.c
+++ b/drivers/video/pnx4008/pnxrgbfb.c
@@ -100,7 +100,6 @@
 		fb_dealloc_cmap(&info->cmap);
 		framebuffer_release(info);
 		platform_set_drvdata(pdev, NULL);
-		kfree(info);
 	}
 
 	pnx4008_free_dum_channel(channel_owned, pdev->id);
@@ -168,23 +167,21 @@
 
 	ret = fb_alloc_cmap(&info->cmap, 256, 0);
 	if (ret < 0)
-		goto err2;
+		goto err1;
 
 	ret = register_framebuffer(info);
 	if (ret < 0)
-		goto err3;
+		goto err2;
 	platform_set_drvdata(pdev, info);
 
 	return 0;
 
-err3:
-	fb_dealloc_cmap(&info->cmap);
 err2:
-	framebuffer_release(info);
+	fb_dealloc_cmap(&info->cmap);
 err1:
 	pnx4008_free_dum_channel(channel_owned, pdev->id);
 err0:
-	kfree(info);
+	framebuffer_release(info);
 err:
 	return ret;
 }
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index bd54cd0..beefab2 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -27,7 +27,6 @@
 #define VERSION		"0.7.8-NEWAPI"
 
 struct tridentfb_par {
-	int vclk;		/* in MHz */
 	void __iomem *io_virt;	/* iospace virtual memory address */
 };
 
@@ -669,27 +668,26 @@
 		 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
 }
 
-/* Use 20.12 fixed-point for NTSC value and frequency calculation */
-#define calc_freq(n, m, k)  ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
-
 /* Set dotclock frequency */
-static void set_vclk(int freq)
+static void set_vclk(unsigned long freq)
 {
 	int m, n, k;
-	int f, fi, d, di;
+	unsigned long f, fi, d, di;
 	unsigned char lo = 0, hi = 0;
 
-	d = 20;
+	d = 20000;
 	for (k = 2; k >= 0; k--)
 		for (m = 0; m < 63; m++)
 			for (n = 0; n < 128; n++) {
-				fi = calc_freq(n, m, k);
+				fi = ((14318l * (n + 8)) / (m + 2)) >> k;
 				if ((di = abs(fi - freq)) < d) {
 					d = di;
 					f = fi;
 					lo = n;
 					hi = (k << 6) | m;
 				}
+				if (fi > freq)
+					break;
 			}
 	if (chip3D) {
 		write3C4(ClockHigh, hi);
@@ -888,6 +886,8 @@
 	struct fb_var_screeninfo *var = &info->var;
 	int bpp = var->bits_per_pixel;
 	unsigned char tmp;
+	unsigned long vclk;
+
 	debug("enter\n");
 	hdispend = var->xres / 8 - 1;
 	hsyncstart = (var->xres + var->right_margin) / 8;
@@ -905,7 +905,6 @@
 	vblankstart = var->yres;
 	vblankend = vtotal + 2;
 
-	enable_mmio();
 	crtc_unlock();
 	write3CE(CyberControl, 8);
 
@@ -1015,11 +1014,11 @@
 	write3X4(Performance, 0x92);
 	write3X4(PCIReg, 0x07);		/* MMIO & PCI read and write burst enable */
 
-	/* convert from picoseconds to MHz */
-	par->vclk = 1000000 / info->var.pixclock;
+	/* convert from picoseconds to kHz */
+	vclk = PICOS2KHZ(info->var.pixclock);
 	if (bpp == 32)
-		par->vclk *= 2;
-	set_vclk(par->vclk);
+		vclk *= 2;
+	set_vclk(vclk);
 
 	write3C4(0, 3);
 	write3C4(1, 1);		/* set char clock 8 dots wide */
diff --git a/fs/dquot.c b/fs/dquot.c
index dfba162..5ac77da 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -1491,6 +1491,16 @@
 
 	/* We need to serialize quota_off() for device */
 	mutex_lock(&dqopt->dqonoff_mutex);
+
+	/*
+	 * Skip everything if there's nothing to do. We have to do this because
+	 * sometimes we are called when fill_super() failed and calling
+	 * sync_fs() in such cases does no good.
+	 */
+	if (!sb_any_quota_enabled(sb) && !sb_any_quota_suspended(sb)) {
+		mutex_unlock(&dqopt->dqonoff_mutex);
+		return 0;
+	}
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		toputinode[cnt] = NULL;
 		if (type != -1 && cnt != type)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 0a13973..c92cc1c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -37,17 +37,11 @@
 {
 	struct dentry *dir;
 
-	dir = dget(dentry->d_parent);
+	dir = dget_parent(dentry);
 	mutex_lock_nested(&(dir->d_inode->i_mutex), I_MUTEX_PARENT);
 	return dir;
 }
 
-static void unlock_parent(struct dentry *dentry)
-{
-	mutex_unlock(&(dentry->d_parent->d_inode->i_mutex));
-	dput(dentry->d_parent);
-}
-
 static void unlock_dir(struct dentry *dir)
 {
 	mutex_unlock(&dir->d_inode->i_mutex);
@@ -426,8 +420,9 @@
 	int rc = 0;
 	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+	struct dentry *lower_dir_dentry;
 
-	lock_parent(lower_dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
 	rc = vfs_unlink(lower_dir_inode, lower_dentry);
 	if (rc) {
 		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
@@ -439,7 +434,7 @@
 	dentry->d_inode->i_ctime = dir->i_ctime;
 	d_drop(dentry);
 out_unlock:
-	unlock_parent(lower_dentry);
+	unlock_dir(lower_dir_dentry);
 	return rc;
 }
 
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index 788995e..6560da1 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -257,12 +257,14 @@
 	mutex_lock(&daemon->mux);
 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
 		rc = 0;
+		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		printk(KERN_WARNING "%s: Attempt to read from zombified "
 		       "daemon\n", __func__);
 		goto out_unlock_daemon;
 	}
 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
 		rc = 0;
+		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		goto out_unlock_daemon;
 	}
 	/* This daemon will not go away so long as this flag is set */
diff --git a/fs/exec.c b/fs/exec.c
index aeaa979..1f8a24a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -736,7 +736,7 @@
 	tsk->active_mm = mm;
 	activate_mm(active_mm, mm);
 	task_unlock(tsk);
-	mm_update_next_owner(mm);
+	mm_update_next_owner(old_mm);
 	arch_pick_mmap_layout(mm);
 	if (old_mm) {
 		up_read(&old_mm->mmap_sem);
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index fbec2ef..b128bdc 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2639,8 +2639,7 @@
 	struct proc_dir_entry *proc;
 	char devname[64];
 
-	snprintf(devname, sizeof(devname) - 1, "%s",
-		bdevname(sb->s_bdev, devname));
+	bdevname(sb->s_bdev, devname);
 	sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4);
 
 	MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats);
@@ -2674,8 +2673,7 @@
 	if (sbi->s_mb_proc == NULL)
 		return -EINVAL;
 
-	snprintf(devname, sizeof(devname) - 1, "%s",
-		bdevname(sb->s_bdev, devname));
+	bdevname(sb->s_bdev, devname);
 	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
 	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
 	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f28cf8b..8092f0d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -804,6 +804,8 @@
 		if (offset == PAGE_CACHE_SIZE)
 			offset = 0;
 
+		if (!fc->big_writes)
+			break;
 	} while (iov_iter_count(ii) && count < fc->max_write &&
 		 req->num_pages < FUSE_MAX_PAGES_PER_REQ && offset == 0);
 
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index dadffa2..bae9486 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -404,6 +404,9 @@
 	/** Is bmap not implemented by fs? */
 	unsigned no_bmap : 1;
 
+	/** Do multi-page cached writes */
+	unsigned big_writes : 1;
+
 	/** The number of requests waiting for completion */
 	atomic_t num_waiting;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 79b6158..fb77e09 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -576,6 +576,8 @@
 				fc->no_lock = 1;
 			if (arg->flags & FUSE_ATOMIC_O_TRUNC)
 				fc->atomic_o_trunc = 1;
+			if (arg->flags & FUSE_BIG_WRITES)
+				fc->big_writes = 1;
 		} else {
 			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
 			fc->no_lock = 1;
@@ -599,7 +601,8 @@
 	arg->major = FUSE_KERNEL_VERSION;
 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
 	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
-	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC;
+	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
+		FUSE_BIG_WRITES;
 	req->in.h.opcode = FUSE_INIT;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(*arg);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index d53b2af..67e1c8b 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -65,6 +65,8 @@
 		BUG();
 		return 0;
 	}
+	if (!tree)
+		return 0;
 	if (tree->node_size >= PAGE_CACHE_SIZE) {
 		nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
 		spin_lock(&tree->hash_lock);
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
index 6890433..8a1f503 100644
--- a/fs/hppfs/Makefile
+++ b/fs/hppfs/Makefile
@@ -1,9 +1,9 @@
 #
-# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com)
+# Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
 # Licensed under the GPL
 #
 
-hppfs-objs := hppfs_kern.o
+hppfs-objs := hppfs.o
 
 obj-y =
-obj-$(CONFIG_HPPFS) += hppfs.o
+obj-$(CONFIG_HPPFS) += $(hppfs-objs)
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs.c
similarity index 91%
rename from fs/hppfs/hppfs_kern.c
rename to fs/hppfs/hppfs.c
index 8601d8e..65077aa 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs.c
@@ -33,7 +33,7 @@
 };
 
 struct hppfs_inode_info {
-        struct dentry *proc_dentry;
+	struct dentry *proc_dentry;
 	struct inode vfs_inode;
 };
 
@@ -52,7 +52,7 @@
 	int i;
 
 	sb = dentry->d_sb;
-	if ((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
+	if (dentry->d_parent != sb->s_root)
 		return 0;
 
 	for (i = 0; i < dentry->d_name.len; i++) {
@@ -136,7 +136,7 @@
 }
 
 static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
-                                  struct nameidata *nd)
+				   struct nameidata *nd)
 {
 	struct dentry *proc_dentry, *new, *parent;
 	struct inode *inode;
@@ -254,6 +254,8 @@
 	int err;
 
 	if (hppfs->contents != NULL) {
+		int rem;
+
 		if (*ppos >= hppfs->len)
 			return 0;
 
@@ -267,8 +269,10 @@
 
 		if (off + count > hppfs->len)
 			count = hppfs->len - off;
-		copy_to_user(buf, &data->contents[off], count);
-		*ppos += count;
+		rem = copy_to_user(buf, &data->contents[off], count);
+		*ppos += count - rem;
+		if (rem > 0)
+			return -EFAULT;
 	} else if (hppfs->host_fd != -1) {
 		err = os_seek_file(hppfs->host_fd, *ppos);
 		if (err) {
@@ -285,21 +289,15 @@
 	return count;
 }
 
-static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len,
-			   loff_t *ppos)
+static ssize_t hppfs_write(struct file *file, const char __user *buf,
+			   size_t len, loff_t *ppos)
 {
 	struct hppfs_private *data = file->private_data;
 	struct file *proc_file = data->proc_file;
 	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
-	int err;
 
 	write = proc_file->f_path.dentry->d_inode->i_fop->write;
-
-	proc_file->f_pos = file->f_pos;
-	err = (*write)(proc_file, buf, len, &proc_file->f_pos);
-	file->f_pos = proc_file->f_pos;
-
-	return err;
+	return (*write)(proc_file, buf, len, ppos);
 }
 
 static int open_host_sock(char *host_file, int *filter_out)
@@ -357,7 +355,7 @@
 
 	if (filter) {
 		while ((n = read_proc(proc_file, data->contents,
-				     sizeof(data->contents), NULL, 0)) > 0)
+				      sizeof(data->contents), NULL, 0)) > 0)
 			os_write_file(fd, data->contents, n);
 		err = os_shutdown_socket(fd, 0, 1);
 		if (err) {
@@ -429,8 +427,8 @@
 static int hppfs_open(struct inode *inode, struct file *file)
 {
 	struct hppfs_private *data;
-	struct dentry *proc_dentry;
 	struct vfsmount *proc_mnt;
+	struct dentry *proc_dentry;
 	char *host_file;
 	int err, fd, type, filter;
 
@@ -492,8 +490,8 @@
 static int hppfs_dir_open(struct inode *inode, struct file *file)
 {
 	struct hppfs_private *data;
-	struct dentry *proc_dentry;
 	struct vfsmount *proc_mnt;
+	struct dentry *proc_dentry;
 	int err;
 
 	err = -ENOMEM;
@@ -620,6 +618,9 @@
 
 void hppfs_delete_inode(struct inode *ino)
 {
+	dput(HPPFS_I(ino)->proc_dentry);
+	mntput(ino->i_sb->s_fs_info);
+
 	clear_inode(ino);
 }
 
@@ -628,69 +629,46 @@
 	kfree(HPPFS_I(inode));
 }
 
-static void hppfs_put_super(struct super_block *sb)
-{
-	mntput(sb->s_fs_info);
-}
-
 static const struct super_operations hppfs_sbops = {
 	.alloc_inode	= hppfs_alloc_inode,
 	.destroy_inode	= hppfs_destroy_inode,
 	.delete_inode	= hppfs_delete_inode,
 	.statfs		= hppfs_statfs,
-	.put_super	= hppfs_put_super,
 };
 
 static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
 			  int buflen)
 {
-	struct file *proc_file;
 	struct dentry *proc_dentry;
-	struct vfsmount *proc_mnt;
-	int ret;
 
 	proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
-	proc_mnt = dentry->d_sb->s_fs_info;
-
-	proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY);
-	if (IS_ERR(proc_file))
-		return PTR_ERR(proc_file);
-
-	ret = proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, buflen);
-
-	fput(proc_file);
-
-	return ret;
+	return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer,
+						    buflen);
 }
 
-static void* hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct file *proc_file;
 	struct dentry *proc_dentry;
-	struct vfsmount *proc_mnt;
-	void *ret;
 
 	proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
-	proc_mnt = dentry->d_sb->s_fs_info;
 
-	proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY);
-	if (IS_ERR(proc_file))
-		return proc_file;
+	return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
+}
 
-	ret = proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
-
-	fput(proc_file);
-
-	return ret;
+int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	return generic_permission(inode, mask, NULL);
 }
 
 static const struct inode_operations hppfs_dir_iops = {
 	.lookup		= hppfs_lookup,
+	.permission	= hppfs_permission,
 };
 
 static const struct inode_operations hppfs_link_iops = {
 	.readlink	= hppfs_readlink,
 	.follow_link	= hppfs_follow_link,
+	.permission	= hppfs_permission,
 };
 
 static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
@@ -712,7 +690,7 @@
 		inode->i_fop = &hppfs_file_fops;
 	}
 
-	HPPFS_I(inode)->proc_dentry = dentry;
+	HPPFS_I(inode)->proc_dentry = dget(dentry);
 
 	inode->i_uid = proc_ino->i_uid;
 	inode->i_gid = proc_ino->i_gid;
@@ -725,7 +703,7 @@
 	inode->i_size = proc_ino->i_size;
 	inode->i_blocks = proc_ino->i_blocks;
 
-	return 0;
+	return inode;
 }
 
 static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 53632e3..2e24567 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -901,7 +901,7 @@
 {
 	char name[BDEVNAME_SIZE];
 
-	snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
+	bdevname(journal->j_dev, name);
 	journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
 	if (journal->j_proc_entry) {
 		proc_create_data("history", S_IRUGO, journal->j_proc_entry,
@@ -915,7 +915,7 @@
 {
 	char name[BDEVNAME_SIZE];
 
-	snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
+	bdevname(journal->j_dev, name);
 	remove_proc_entry("info", journal->j_proc_entry);
 	remove_proc_entry("history", journal->j_proc_entry);
 	remove_proc_entry(name, proc_jbd2_stats);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index dca997a..9e3b8c3 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -298,6 +298,7 @@
 	render_cap_t(m, "CapInh:\t", &p->cap_inheritable);
 	render_cap_t(m, "CapPrm:\t", &p->cap_permitted);
 	render_cap_t(m, "CapEff:\t", &p->cap_effective);
+	render_cap_t(m, "CapBnd:\t", &p->cap_bset);
 }
 
 static inline void task_context_switch_counts(struct seq_file *m,
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index 244a1aa..11c0351 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -107,7 +107,6 @@
 
 /* inode.c */
 extern struct inode *ufs_iget(struct super_block *, unsigned long);
-extern void ufs_put_inode (struct inode *);
 extern int ufs_write_inode (struct inode *, int);
 extern int ufs_sync_inode (struct inode *);
 extern void ufs_delete_inode (struct inode *);
diff --git a/include/asm-alpha/barrier.h b/include/asm-alpha/barrier.h
index 384dc08..ac78eba 100644
--- a/include/asm-alpha/barrier.h
+++ b/include/asm-alpha/barrier.h
@@ -24,7 +24,7 @@
 #define smp_mb()	barrier()
 #define smp_rmb()	barrier()
 #define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	barrier()
+#define smp_read_barrier_depends()	do { } while (0)
 #endif
 
 #define set_mb(var, value) \
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 05ce5fb..3f0c59f 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -287,17 +287,34 @@
 #define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 #define pgd_offset(mm, address)	((mm)->pgd+pgd_index(address))
 
+/*
+ * The smp_read_barrier_depends() in the following functions are required to
+ * order the load of *dir (the pointer in the top level page table) with any
+ * subsequent load of the returned pmd_t *ret (ret is data dependent on *dir).
+ *
+ * If this ordering is not enforced, the CPU might load an older value of
+ * *ret, which may be uninitialized data. See mm/memory.c:__pte_alloc for
+ * more details.
+ *
+ * Note that we never change the mm->pgd pointer after the task is running, so
+ * pgd_offset does not require such a barrier.
+ */
+
 /* Find an entry in the second-level page table.. */
 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
-	return (pmd_t *) pgd_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
+	pmd_t *ret = (pmd_t *) pgd_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
+	smp_read_barrier_depends(); /* see above */
+	return ret;
 }
 
 /* Find an entry in the third-level page table.. */
 extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)
 {
-	return (pte_t *) pmd_page_vaddr(*dir)
+	pte_t *ret = (pte_t *) pmd_page_vaddr(*dir)
 		+ ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1));
+	smp_read_barrier_depends(); /* see above */
+	return ret;
 }
 
 #define pte_offset_map(dir,addr)	pte_offset_kernel((dir),(addr))
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index cb307f8..d3a12a9 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -179,7 +179,7 @@
 #define mb()			asm volatile ("membar" : : :"memory")
 #define rmb()			asm volatile ("membar" : : :"memory")
 #define wmb()			asm volatile ("membar" : : :"memory")
-#define read_barrier_depends()	barrier()
+#define read_barrier_depends()	do { } while (0)
 
 #ifdef CONFIG_SMP
 #define smp_mb()			mb()
diff --git a/include/asm-um/irq.h b/include/asm-um/irq.h
index de389a4..4a2037f 100644
--- a/include/asm-um/irq.h
+++ b/include/asm-um/irq.h
@@ -15,8 +15,9 @@
 #define SIGIO_WRITE_IRQ 	11
 #define TELNETD_IRQ 		12
 #define XTERM_IRQ 		13
+#define RANDOM_IRQ 		14
 
-#define LAST_IRQ XTERM_IRQ
+#define LAST_IRQ RANDOM_IRQ
 #define NR_IRQS (LAST_IRQ + 1)
 
 #endif
diff --git a/include/asm-um/keyboard.h b/include/asm-um/keyboard.h
deleted file mode 100644
index ee2e230..0000000
--- a/include/asm-um/keyboard.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_KEYBOARD_H
-#define __UM_KEYBOARD_H
-
-#include "asm/arch/keyboard.h"
-
-#endif
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 381f96b..916e1a6 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -7,16 +7,20 @@
 #ifndef __UM_PAGE_H
 #define __UM_PAGE_H
 
+#include <linux/const.h>
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(_AC(1, UL) << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+#ifndef __ASSEMBLY__
+
 struct page;
 
 #include <linux/types.h>
 #include <asm/vm-flags.h>
 
-/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT	12
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
-#define PAGE_MASK	(~(PAGE_SIZE-1))
-
 /*
  * These are used to make use of C type-checking..
  */
@@ -120,4 +124,5 @@
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif
+#endif	/* __ASSEMBLY__ */
+#endif	/* __UM_PAGE_H */
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 43b406d..1abfe66 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -110,7 +110,6 @@
 
 extern int bitmap_scnprintf(char *buf, unsigned int len,
 			const unsigned long *src, int nbits);
-extern int bitmap_scnprintf_len(unsigned int len);
 extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
 			unsigned long *dst, int nbits);
 extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 9650806..5df3db5 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -289,13 +289,6 @@
 	return bitmap_scnprintf(buf, len, srcp->bits, nbits);
 }
 
-#define cpumask_scnprintf_len(len) \
-			__cpumask_scnprintf_len((len))
-static inline int __cpumask_scnprintf_len(int len)
-{
-	return bitmap_scnprintf_len(len);
-}
-
 #define cpumask_parse_user(ubuf, ulen, dst) \
 			__cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS)
 static inline int __cpumask_parse_user(const char __user *buf, int len,
diff --git a/include/linux/device.h b/include/linux/device.h
index 8c23e3d..15e9fa3 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -183,7 +183,6 @@
 	struct module		*owner;
 
 	struct kset		subsys;
-	struct list_head	children;
 	struct list_head	devices;
 	struct list_head	interfaces;
 	struct kset		class_dirs;
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 5c86f11..d482821 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -109,6 +109,7 @@
 #define FUSE_POSIX_LOCKS	(1 << 1)
 #define FUSE_FILE_OPS		(1 << 2)
 #define FUSE_ATOMIC_O_TRUNC	(1 << 3)
+#define FUSE_BIG_WRITES		(1 << 5)
 
 /**
  * Release flags
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index e9874e7..ae7aec3 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -525,7 +525,7 @@
 #define ADDPART_FLAG_RAID	1
 #define ADDPART_FLAG_WHOLEDISK	2
 
-extern dev_t blk_lookup_devt(const char *name);
+extern dev_t blk_lookup_devt(const char *name, int part);
 extern char *disk_name (struct gendisk *hd, int part, char *buf);
 
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
@@ -553,7 +553,7 @@
 
 static inline void printk_all_partitions(void) { }
 
-static inline dev_t blk_lookup_devt(const char *name)
+static inline dev_t blk_lookup_devt(const char *name, int part)
 {
 	dev_t devt = MKDEV(0, 0);
 	return devt;
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index eb7c16c..02a27ae 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -226,8 +226,17 @@
 	rwlock_t		ioctx_list_lock;	/* aio lock */
 	struct kioctx		*ioctx_list;
 #ifdef CONFIG_MM_OWNER
-	struct task_struct *owner;	/* The thread group leader that */
-					/* owns the mm_struct.		*/
+	/*
+	 * "owner" points to a task that is regarded as the canonical
+	 * user/owner of this mm. All of the following must be true in
+	 * order for it to be changed:
+	 *
+	 * current == mm->owner
+	 * current->mm != mm
+	 * new_owner->mm == mm
+	 * new_owner->alloc_lock is held
+	 */
+	struct task_struct *owner;
 #endif
 
 #ifdef CONFIG_PROC_FS
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7c1d446..b11e6e1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -93,14 +93,16 @@
  *	used.
  */
  
-#if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR)
-#define LL_MAX_HEADER	32
+#if defined(CONFIG_WLAN_80211) || defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+# if defined(CONFIG_MAC80211_MESH)
+#  define LL_MAX_HEADER 128
+# else
+#  define LL_MAX_HEADER 96
+# endif
+#elif defined(CONFIG_TR)
+# define LL_MAX_HEADER 48
 #else
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-#define LL_MAX_HEADER	96
-#else
-#define LL_MAX_HEADER	48
-#endif
+# define LL_MAX_HEADER 32
 #endif
 
 #if !defined(CONFIG_NET_IPIP) && !defined(CONFIG_NET_IPIP_MODULE) && \
@@ -244,11 +246,16 @@
  *
  * We could use other alignment values, but we must maintain the
  * relationship HH alignment <= LL alignment.
+ *
+ * LL_ALLOCATED_SPACE also takes into account the tailroom the device
+ * may need.
  */
 #define LL_RESERVED_SPACE(dev) \
-	(((dev)->hard_header_len&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+	((((dev)->hard_header_len+(dev)->needed_headroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 #define LL_RESERVED_SPACE_EXTRA(dev,extra) \
-	((((dev)->hard_header_len+extra)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+	((((dev)->hard_header_len+(dev)->needed_headroom+(extra))&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+#define LL_ALLOCATED_SPACE(dev) \
+	((((dev)->hard_header_len+(dev)->needed_headroom+(dev)->needed_tailroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 
 struct header_ops {
 	int	(*create) (struct sk_buff *skb, struct net_device *dev,
@@ -567,6 +574,13 @@
 	unsigned short		type;	/* interface hardware type	*/
 	unsigned short		hard_header_len;	/* hardware hdr length	*/
 
+	/* extra head- and tailroom the hardware may need, but not in all cases
+	 * can this be guaranteed, especially tailroom. Some cases also use
+	 * LL_MAX_HEADER instead to allocate the skb.
+	 */
+	unsigned short		needed_headroom;
+	unsigned short		needed_tailroom;
+
 	struct net_device	*master; /* Pointer to master device of a group,
 					  * which this device is member of.
 					  */
@@ -715,6 +729,9 @@
 	struct net		*nd_net;
 #endif
 
+	/* mid-layer private */
+	void			*ml_priv;
+
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
 	/* macvlan */
diff --git a/include/linux/usb/association.h b/include/linux/usb/association.h
new file mode 100644
index 0000000..07c5e3c
--- /dev/null
+++ b/include/linux/usb/association.h
@@ -0,0 +1,150 @@
+/*
+ * Wireless USB - Cable Based Association
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_USB_ASSOCIATION_H
+#define __LINUX_USB_ASSOCIATION_H
+
+
+/*
+ * Association attributes
+ *
+ * Association Models Supplement to WUSB 1.0 T[3-1]
+ *
+ * Each field in the structures has it's ID, it's length and then the
+ * value. This is the actual definition of the field's ID and its
+ * length.
+ */
+struct wusb_am_attr {
+	__u8 id;
+	__u8 len;
+};
+
+/* Different fields defined by the spec */
+#define WUSB_AR_AssociationTypeId	{ .id = 0x0000, .len =  2 }
+#define WUSB_AR_AssociationSubTypeId	{ .id = 0x0001, .len =  2 }
+#define WUSB_AR_Length			{ .id = 0x0002, .len =  4 }
+#define WUSB_AR_AssociationStatus	{ .id = 0x0004, .len =  4 }
+#define WUSB_AR_LangID			{ .id = 0x0008, .len =  2 }
+#define WUSB_AR_DeviceFriendlyName	{ .id = 0x000b, .len = 64 } /* max */
+#define WUSB_AR_HostFriendlyName	{ .id = 0x000c, .len = 64 } /* max */
+#define WUSB_AR_CHID			{ .id = 0x1000, .len = 16 }
+#define WUSB_AR_CDID			{ .id = 0x1001, .len = 16 }
+#define WUSB_AR_ConnectionContext	{ .id = 0x1002, .len = 48 }
+#define WUSB_AR_BandGroups		{ .id = 0x1004, .len =  2 }
+
+/* CBAF Control Requests (AMS1.0[T4-1] */
+enum {
+	CBAF_REQ_GET_ASSOCIATION_INFORMATION = 0x01,
+	CBAF_REQ_GET_ASSOCIATION_REQUEST,
+	CBAF_REQ_SET_ASSOCIATION_RESPONSE
+};
+
+/*
+ * CBAF USB-interface defitions
+ *
+ * No altsettings, one optional interrupt endpoint.
+ */
+enum {
+	CBAF_IFACECLASS    = 0xef,
+	CBAF_IFACESUBCLASS = 0x03,
+	CBAF_IFACEPROTOCOL = 0x01,
+};
+
+/* Association Information (AMS1.0[T4-3]) */
+struct wusb_cbaf_assoc_info {
+	__le16 Length;
+	__u8 NumAssociationRequests;
+	__le16 Flags;
+	__u8 AssociationRequestsArray[];
+} __attribute__((packed));
+
+/* Association Request (AMS1.0[T4-4]) */
+struct wusb_cbaf_assoc_request {
+	__u8 AssociationDataIndex;
+	__u8 Reserved;
+	__le16 AssociationTypeId;
+	__le16 AssociationSubTypeId;
+	__le32 AssociationTypeInfoSize;
+} __attribute__((packed));
+
+enum {
+	AR_TYPE_WUSB                    = 0x0001,
+	AR_TYPE_WUSB_RETRIEVE_HOST_INFO = 0x0000,
+	AR_TYPE_WUSB_ASSOCIATE          = 0x0001,
+};
+
+/* Association Attribute header (AMS1.0[3.8]) */
+struct wusb_cbaf_attr_hdr {
+	__le16 id;
+	__le16 len;
+} __attribute__((packed));
+
+/* Host Info (AMS1.0[T4-7]) (yeah, more headers and fields...) */
+struct wusb_cbaf_host_info {
+	struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+	__le16 AssociationTypeId;
+	struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+	__le16 AssociationSubTypeId;
+	struct wusb_cbaf_attr_hdr CHID_hdr;
+	struct wusb_ckhdid CHID;
+	struct wusb_cbaf_attr_hdr LangID_hdr;
+	__le16 LangID;
+	struct wusb_cbaf_attr_hdr HostFriendlyName_hdr;
+	__u8 HostFriendlyName[];
+} __attribute__((packed));
+
+/* Device Info (AMS1.0[T4-8])
+ *
+ * I still don't get this tag'n'header stuff for each goddamn
+ * field...
+ */
+struct wusb_cbaf_device_info {
+	struct wusb_cbaf_attr_hdr Length_hdr;
+	__le32 Length;
+	struct wusb_cbaf_attr_hdr CDID_hdr;
+	struct wusb_ckhdid CDID;
+	struct wusb_cbaf_attr_hdr BandGroups_hdr;
+	__le16 BandGroups;
+	struct wusb_cbaf_attr_hdr LangID_hdr;
+	__le16 LangID;
+	struct wusb_cbaf_attr_hdr DeviceFriendlyName_hdr;
+	__u8 DeviceFriendlyName[];
+} __attribute__((packed));
+
+/* Connection Context; CC_DATA - Success case (AMS1.0[T4-9]) */
+struct wusb_cbaf_cc_data {
+	struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+	__le16 AssociationTypeId;
+	struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+	__le16 AssociationSubTypeId;
+	struct wusb_cbaf_attr_hdr Length_hdr;
+	__le32 Length;
+	struct wusb_cbaf_attr_hdr ConnectionContext_hdr;
+	struct wusb_ckhdid CHID;
+	struct wusb_ckhdid CDID;
+	struct wusb_ckhdid CK;
+	struct wusb_cbaf_attr_hdr BandGroups_hdr;
+	__le16 BandGroups;
+} __attribute__((packed));
+
+/* CC_DATA - Failure case (AMS1.0[T4-10]) */
+struct wusb_cbaf_cc_data_fail {
+	struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+	__le16 AssociationTypeId;
+	struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+	__le16 AssociationSubTypeId;
+	struct wusb_cbaf_attr_hdr Length_hdr;
+	__le16 Length;
+	struct wusb_cbaf_attr_hdr AssociationStatus_hdr;
+	__u32 AssociationStatus;
+} __attribute__((packed));
+
+#endif	/* __LINUX_USB_ASSOCIATION_H */
diff --git a/include/net/irda/discovery.h b/include/net/irda/discovery.h
index e4efad1..0ce9339 100644
--- a/include/net/irda/discovery.h
+++ b/include/net/irda/discovery.h
@@ -57,9 +57,6 @@
 	__u8  byte[2];
 } __u16_host_order;
 
-/* Same purpose, different application */
-#define u16ho(array) (* ((__u16 *) array))
-
 /* Types of discovery */
 typedef enum {
 	DISCOVERY_LOG,		/* What's in our discovery log */
diff --git a/include/net/syncppp.h b/include/net/syncppp.h
index 877efa4..e43f407 100644
--- a/include/net/syncppp.h
+++ b/include/net/syncppp.h
@@ -59,7 +59,7 @@
 
 static inline struct sppp *sppp_of(struct net_device *dev) 
 {
-	struct ppp_device **ppp = dev->priv;
+	struct ppp_device **ppp = dev->ml_priv;
 	BUG_ON((*ppp)->dev != dev);
 	return &(*ppp)->sppp;
 }
diff --git a/include/sound/soc.h b/include/sound/soc.h
index e6ea6f7..d3c8c03 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -238,7 +238,7 @@
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
-#define snd_soc_info_bool_ext		snd_ctl_boolean_mono
+#define snd_soc_info_bool_ext		snd_ctl_boolean_mono_info
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 3885e70..660c1e5 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -76,6 +76,7 @@
 	char s[32];
 	char *p;
 	dev_t res = 0;
+	int part;
 
 	if (strncmp(name, "/dev/", 5) != 0) {
 		unsigned maj, min;
@@ -106,7 +107,31 @@
 	for (p = s; *p; p++)
 		if (*p == '/')
 			*p = '!';
-	res = blk_lookup_devt(s);
+	res = blk_lookup_devt(s, 0);
+	if (res)
+		goto done;
+
+	/*
+	 * try non-existant, but valid partition, which may only exist
+	 * after revalidating the disk, like partitioned md devices
+	 */
+	while (p > s && isdigit(p[-1]))
+		p--;
+	if (p == s || !*p || *p == '0')
+		goto fail;
+
+	/* try disk name without <part number> */
+	part = simple_strtoul(p, NULL, 10);
+	*p = '\0';
+	res = blk_lookup_devt(s, part);
+	if (res)
+		goto done;
+
+	/* try disk name without p<part number> */
+	if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
+		goto fail;
+	p[-1] = '\0';
+	res = blk_lookup_devt(s, part);
 	if (res)
 		goto done;
 
diff --git a/init/main.c b/init/main.c
index ddada7a..f406fef 100644
--- a/init/main.c
+++ b/init/main.c
@@ -702,7 +702,6 @@
 
 	for (call = __initcall_start; call < __initcall_end; call++) {
 		ktime_t t0, t1, delta;
-		char *msg = NULL;
 		char msgbuf[40];
 		int result;
 
@@ -724,22 +723,23 @@
 				(unsigned long long) delta.tv64 >> 20);
 		}
 
-		if (result && result != -ENODEV && initcall_debug) {
-			sprintf(msgbuf, "error code %d", result);
-			msg = msgbuf;
-		}
+		msgbuf[0] = 0;
+
+		if (result && result != -ENODEV && initcall_debug)
+			sprintf(msgbuf, "error code %d ", result);
+
 		if (preempt_count() != count) {
-			msg = "preemption imbalance";
+			strncat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
 			preempt_count() = count;
 		}
 		if (irqs_disabled()) {
-			msg = "disabled interrupts";
+			strncat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
 			local_irq_enable();
 		}
-		if (msg) {
+		if (msgbuf[0]) {
 			print_fn_descriptor_symbol(KERN_WARNING "initcall %s()",
 					(unsigned long) *call);
-			printk(" returned with %s\n", msg);
+			printk(" returned with %s\n", msgbuf);
 		}
 	}
 
diff --git a/lib/bitmap.c b/lib/bitmap.c
index c4cb48f..482df94 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -316,22 +316,6 @@
 EXPORT_SYMBOL(bitmap_scnprintf);
 
 /**
- * bitmap_scnprintf_len - return buffer length needed to convert
- * bitmap to an ASCII hex string.
- * @len: number of bits to be converted
- */
-int bitmap_scnprintf_len(unsigned int len)
-{
-	/* we need 9 chars per word for 32 bit words (8 hexdigits + sep/null) */
-	int bitslen = ALIGN(len, CHUNKSZ);
-	int wordlen = CHUNKSZ / 4;
-	int buflen = (bitslen / wordlen) * (wordlen + 1) * sizeof(char);
-
-	return buflen;
-}
-EXPORT_SYMBOL(bitmap_scnprintf_len);
-
-/**
  * __bitmap_parse - convert an ASCII hex string into a bitmap.
  * @buf: pointer to buffer containing string.
  * @buflen: buffer size in bytes.  If string is smaller than this
diff --git a/mm/memory.c b/mm/memory.c
index 48c122d..fb5608a 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -311,6 +311,21 @@
 	if (!new)
 		return -ENOMEM;
 
+	/*
+	 * Ensure all pte setup (eg. pte page lock and page clearing) are
+	 * visible before the pte is made visible to other CPUs by being
+	 * put into page tables.
+	 *
+	 * The other side of the story is the pointer chasing in the page
+	 * table walking code (when walking the page table without locking;
+	 * ie. most of the time). Fortunately, these data accesses consist
+	 * of a chain of data-dependent loads, meaning most CPUs (alpha
+	 * being the notable exception) will already guarantee loads are
+	 * seen in-order. See the alpha page table accessors for the
+	 * smp_read_barrier_depends() barriers in page table walking code.
+	 */
+	smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
+
 	spin_lock(&mm->page_table_lock);
 	if (!pmd_present(*pmd)) {	/* Has another populated it ? */
 		mm->nr_ptes++;
@@ -329,6 +344,8 @@
 	if (!new)
 		return -ENOMEM;
 
+	smp_wmb(); /* See comment in __pte_alloc */
+
 	spin_lock(&init_mm.page_table_lock);
 	if (!pmd_present(*pmd)) {	/* Has another populated it ? */
 		pmd_populate_kernel(&init_mm, pmd, new);
@@ -2619,6 +2636,8 @@
 	if (!new)
 		return -ENOMEM;
 
+	smp_wmb(); /* See comment in __pte_alloc */
+
 	spin_lock(&mm->page_table_lock);
 	if (pgd_present(*pgd))		/* Another has populated it */
 		pud_free(mm, new);
@@ -2640,6 +2659,8 @@
 	if (!new)
 		return -ENOMEM;
 
+	smp_wmb(); /* See comment in __pte_alloc */
+
 	spin_lock(&mm->page_table_lock);
 #ifndef __ARCH_HAS_4LEVEL_HACK
 	if (pud_present(*pud))		/* Another has populated it */
diff --git a/mm/pdflush.c b/mm/pdflush.c
index 1c96cfc..9d834aa 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -207,7 +207,6 @@
 
 	spin_lock_irqsave(&pdflush_lock, flags);
 	if (list_empty(&pdflush_list)) {
-		spin_unlock_irqrestore(&pdflush_lock, flags);
 		ret = -1;
 	} else {
 		struct pdflush_work *pdf;
@@ -219,8 +218,9 @@
 		pdf->fn = fn;
 		pdf->arg0 = arg0;
 		wake_up_process(pdf->who);
-		spin_unlock_irqrestore(&pdflush_lock, flags);
 	}
+	spin_unlock_irqrestore(&pdflush_lock, flags);
+
 	return ret;
 }
 
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 1a32130..db9eabb 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -41,7 +41,9 @@
 */
 void all_vm_events(unsigned long *ret)
 {
+	get_online_cpus();
 	sum_vm_events(ret, &cpu_online_map);
+	put_online_cpus();
 }
 EXPORT_SYMBOL_GPL(all_vm_events);
 
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b04d643..8fb134d 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -419,7 +419,7 @@
 		return;
 
 	size = arp_hdr_len(skb->dev);
-	send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
+	send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
 			    LL_RESERVED_SPACE(np->dev));
 
 	if (!send_skb)
diff --git a/net/core/sock.c b/net/core/sock.c
index fa76f04..88094cb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -270,7 +270,7 @@
 	int err = 0;
 	int skb_len;
 
-	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
+	/* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
 	   number of warnings when compiling with -W --ANK
 	 */
 	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 68d1544..7c9bb13 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -340,7 +340,7 @@
 
 		dev_hold(dev);
 
-		skb = sock_alloc_send_skb(sk, len+LL_RESERVED_SPACE(dev),
+		skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
 					  msg->msg_flags & MSG_DONTWAIT, &err);
 		if (skb==NULL)
 			goto out_unlock;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 68b72a7..418862f 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -570,7 +570,7 @@
 	 *	Allocate a buffer
 	 */
 
-	skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+	skb = alloc_skb(arp_hdr_len(dev) + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL)
 		return NULL;
 
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 05afb57..2c0e457 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -338,7 +338,7 @@
 		return -ENOENT;
 
 	hash = cipso_v4_map_cache_hash(key, key_len);
-	bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+	bkt = hash & (CIPSO_V4_CACHE_BUCKETS - 1);
 	spin_lock_bh(&cipso_v4_cache[bkt].lock);
 	list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
 		if (entry->hash == hash &&
@@ -417,7 +417,7 @@
 	atomic_inc(&secattr->cache->refcount);
 	entry->lsm_data = secattr->cache;
 
-	bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+	bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
 	spin_lock_bh(&cipso_v4_cache[bkt].lock);
 	if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
 		list_add(&entry->list, &cipso_v4_cache[bkt].list);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 6250f42..2769dc4 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -292,7 +292,7 @@
 	struct iphdr *pip;
 	struct igmpv3_report *pig;
 
-	skb = alloc_skb(size + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+	skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL)
 		return NULL;
 
@@ -653,7 +653,7 @@
 		return -1;
 	}
 
-	skb=alloc_skb(IGMP_SIZE+LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+	skb=alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL) {
 		ip_rt_put(rt);
 		return -1;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 89dee43..ed45037 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -710,14 +710,14 @@
 	struct net_device *dev = d->dev;
 	struct sk_buff *skb;
 	struct bootp_pkt *b;
-	int hh_len = LL_RESERVED_SPACE(dev);
 	struct iphdr *h;
 
 	/* Allocate packet */
-	skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+	skb = alloc_skb(sizeof(struct bootp_pkt) + LL_ALLOCATED_SPACE(dev) + 15,
+			GFP_KERNEL);
 	if (!skb)
 		return;
-	skb_reserve(skb, hh_len);
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 	b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
 	memset(b, 0, sizeof(struct bootp_pkt));
 
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 11d7f75..fead049 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -322,7 +322,6 @@
 			unsigned int flags)
 {
 	struct inet_sock *inet = inet_sk(sk);
-	int hh_len;
 	struct iphdr *iph;
 	struct sk_buff *skb;
 	unsigned int iphlen;
@@ -336,13 +335,12 @@
 	if (flags&MSG_PROBE)
 		goto out;
 
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
-	skb = sock_alloc_send_skb(sk, length+hh_len+15,
-				  flags&MSG_DONTWAIT, &err);
+	skb = sock_alloc_send_skb(sk,
+				  length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+				  flags & MSG_DONTWAIT, &err);
 	if (skb == NULL)
 		goto error;
-	skb_reserve(skb, hh_len);
+	skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 26c9369..b54d9d3 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1842,9 +1842,16 @@
 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 		}
 
-		/* Don't lost mark skbs that were fwd transmitted after RTO */
-		if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) &&
-		    !after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) {
+		/* Marking forward transmissions that were made after RTO lost
+		 * can cause unnecessary retransmissions in some scenarios,
+		 * SACK blocks will mitigate that in some but not in all cases.
+		 * We used to not mark them but it was causing break-ups with
+		 * receivers that do only in-order receival.
+		 *
+		 * TODO: we could detect presence of such receiver and select
+		 * different behavior per flow.
+		 */
+		if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
 			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 			tp->lost_out += tcp_skb_pcount(skb);
 		}
@@ -1860,7 +1867,7 @@
 	tp->reordering = min_t(unsigned int, tp->reordering,
 			       sysctl_tcp_reordering);
 	tcp_set_ca_state(sk, TCP_CA_Loss);
-	tp->high_seq = tp->frto_highmark;
+	tp->high_seq = tp->snd_nxt;
 	TCP_ECN_queue_cwr(tp);
 
 	tcp_clear_retrans_hints_partial(tp);
@@ -2482,7 +2489,7 @@
 
 	tcp_verify_left_out(tp);
 
-	if (tp->retrans_out == 0)
+	if (!tp->frto_counter && tp->retrans_out == 0)
 		tp->retrans_stamp = 0;
 
 	if (flag & FLAG_ECE)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 0af2e05..48cdce9 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -780,7 +780,7 @@
 		 *	Allocate buffer.
 		 */
 
-		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
 			NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
 			IP6_INC_STATS(ip6_dst_idev(skb->dst),
 				      IPSTATS_MIB_FRAGFAILS);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 54f91ef..fd632dd 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1411,7 +1411,7 @@
 		     IPV6_TLV_PADN, 0 };
 
 	/* we assume size > sizeof(ra) here */
-	skb = sock_alloc_send_skb(sk, size + LL_RESERVED_SPACE(dev), 1, &err);
+	skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err);
 
 	if (!skb)
 		return NULL;
@@ -1790,7 +1790,7 @@
 	payload_len = len + sizeof(ra);
 	full_len = sizeof(struct ipv6hdr) + payload_len;
 
-	skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err);
+	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err);
 
 	if (skb == NULL) {
 		rcu_read_lock();
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2c74885..a55fc05 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -479,7 +479,7 @@
 
 	skb = sock_alloc_send_skb(sk,
 				  (MAX_HEADER + sizeof(struct ipv6hdr) +
-				   len + LL_RESERVED_SPACE(dev)),
+				   len + LL_ALLOCATED_SPACE(dev)),
 				  1, &err);
 	if (!skb) {
 		ND_PRINTK0(KERN_ERR
@@ -1521,7 +1521,7 @@
 
 	buff = sock_alloc_send_skb(sk,
 				   (MAX_HEADER + sizeof(struct ipv6hdr) +
-				    len + LL_RESERVED_SPACE(dev)),
+				    len + LL_ALLOCATED_SPACE(dev)),
 				   1, &err);
 	if (buff == NULL) {
 		ND_PRINTK0(KERN_ERR
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 396f0ea..232e0dc 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -609,7 +609,6 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6hdr *iph;
 	struct sk_buff *skb;
-	unsigned int hh_len;
 	int err;
 
 	if (length > rt->u.dst.dev->mtu) {
@@ -619,13 +618,12 @@
 	if (flags&MSG_PROBE)
 		goto out;
 
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
-	skb = sock_alloc_send_skb(sk, length+hh_len+15,
-				  flags&MSG_DONTWAIT, &err);
+	skb = sock_alloc_send_skb(sk,
+				  length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+				  flags & MSG_DONTWAIT, &err);
 	if (skb == NULL)
 		goto error;
-	skb_reserve(skb, hh_len);
+	skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index bfacef8..a6f99b5 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -40,6 +40,8 @@
 
 #include <net/irda/discovery.h>
 
+#include <asm/unaligned.h>
+
 /*
  * Function irlmp_add_discovery (cachelog, discovery)
  *
@@ -87,7 +89,7 @@
 			 */
 			hashbin_remove_this(cachelog, (irda_queue_t *) node);
 			/* Check if hints bits are unchanged */
-			if(u16ho(node->data.hints) == u16ho(new->data.hints))
+			if (get_unaligned((__u16 *)node->data.hints) == get_unaligned((__u16 *)new->data.hints))
 				/* Set time of first discovery for this node */
 				new->firststamp = node->firststamp;
 			kfree(node);
@@ -281,9 +283,9 @@
 		/* Mask out the ones we don't want :
 		 * We want to match the discovery mask, and to get only
 		 * the most recent one (unless we want old ones) */
-		if ((u16ho(discovery->data.hints) & mask) &&
+		if ((get_unaligned((__u16 *)discovery->data.hints) & mask) &&
 		    ((old_entries) ||
-		     ((jiffies - discovery->firststamp) < j_timeout)) ) {
+		     ((jiffies - discovery->firststamp) < j_timeout))) {
 			/* Create buffer as needed.
 			 * As this function get called a lot and most time
 			 * we don't have anything to put in the log (we are
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 1f81f8e..7bf5b91 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -1062,7 +1062,8 @@
 		for(i = 0; i < number; i++) {
 			/* Check if we should notify client */
 			if ((client->expir_callback) &&
-			    (client->hint_mask.word & u16ho(expiries[i].hints)
+			    (client->hint_mask.word &
+			     get_unaligned((__u16 *)expiries[i].hints)
 			     & 0x7f7f) )
 				client->expir_callback(&(expiries[i]),
 						       EXPIRY_TIMEOUT,
@@ -1086,7 +1087,7 @@
 
 	IRDA_ASSERT(irlmp != NULL, return NULL;);
 
-	u16ho(irlmp->discovery_rsp.data.hints) = irlmp->hints.word;
+	put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints);
 
 	/*
 	 *  Set character set for device name (we use ASCII), and
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
index 75497e5..a3ec002 100644
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -1673,7 +1673,7 @@
   /* Notify the control channel */
   irnet_post_event(NULL, IRNET_DISCOVER,
 		   discovery->saddr, discovery->daddr, discovery->info,
-		   u16ho(discovery->hints));
+		   get_unaligned((__u16 *)discovery->hints));
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
@@ -1704,7 +1704,7 @@
   /* Notify the control channel */
   irnet_post_event(NULL, IRNET_EXPIRE,
 		   expiry->saddr, expiry->daddr, expiry->info,
-		   u16ho(expiry->hints));
+		   get_unaligned((__u16 *)expiry->hints));
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 879e721..19efc3a 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -255,14 +255,23 @@
 void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
 {
 	char buf[50];
+	struct ieee80211_key *key;
 
 	if (!sdata->debugfsdir)
 		return;
 
-	sprintf(buf, "../keys/%d", sdata->default_key->debugfs.cnt);
-	sdata->debugfs.default_key =
-		debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
+	/* this is running under the key lock */
+
+	key = sdata->default_key;
+	if (key) {
+		sprintf(buf, "../keys/%d", key->debugfs.cnt);
+		sdata->debugfs.default_key =
+			debugfs_create_symlink("default_key",
+					       sdata->debugfsdir, buf);
+	} else
+		ieee80211_debugfs_key_remove_default(sdata);
 }
+
 void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
 {
 	if (!sdata)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 80954a5..06e88a5 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -54,6 +54,15 @@
 	if (!ndev)
 		return -ENOMEM;
 
+	ndev->needed_headroom = local->tx_headroom +
+				4*6 /* four MAC addresses */
+				+ 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
+				+ 6 /* mesh */
+				+ 8 /* rfc1042/bridge tunnel */
+				- ETH_HLEN /* ethernet hard_header_len */
+				+ IEEE80211_ENCRYPT_HEADROOM;
+	ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
+
 	ret = dev_alloc_name(ndev, ndev->name);
 	if (ret < 0)
 		goto fail;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index f76bc26..697ef67 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -397,7 +397,7 @@
 	put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum);
 	sdata->u.sta.mesh_seqnum++;
 
-	return 5;
+	return 6;
 }
 
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 3df8092..af0cd1e 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -120,7 +120,7 @@
 		*pos++ = WLAN_EID_PREP;
 		break;
 	default:
-		kfree(skb);
+		kfree_skb(skb);
 		return -ENOTSUPP;
 		break;
 	}
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 5845dc2..99c2d36 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -158,19 +158,25 @@
 	if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
 		return -ENOSPC;
 
-	read_lock(&pathtbl_resize_lock);
-
 	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
 	if (!new_mpath) {
 		atomic_dec(&sdata->u.sta.mpaths);
 		err = -ENOMEM;
 		goto endadd2;
 	}
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	if (!new_node) {
+		kfree(new_mpath);
+		atomic_dec(&sdata->u.sta.mpaths);
+		err = -ENOMEM;
+		goto endadd2;
+	}
+
+	read_lock(&pathtbl_resize_lock);
 	memcpy(new_mpath->dst, dst, ETH_ALEN);
 	new_mpath->dev = dev;
 	new_mpath->flags = 0;
 	skb_queue_head_init(&new_mpath->frame_queue);
-	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
 	new_node->mpath = new_mpath;
 	new_mpath->timer.data = (unsigned long) new_mpath;
 	new_mpath->timer.function = mesh_path_timer;
@@ -202,7 +208,6 @@
 
 endadd:
 	spin_unlock(&mesh_paths->hashwlock[hash_idx]);
-endadd2:
 	read_unlock(&pathtbl_resize_lock);
 	if (!err && grow) {
 		struct mesh_table *oldtbl, *newtbl;
@@ -215,10 +220,12 @@
 			return -ENOMEM;
 		}
 		rcu_assign_pointer(mesh_paths, newtbl);
+		write_unlock(&pathtbl_resize_lock);
+
 		synchronize_rcu();
 		mesh_table_free(oldtbl, false);
-		write_unlock(&pathtbl_resize_lock);
 	}
+endadd2:
 	return err;
 }
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a5e5c31..4adba09 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -665,6 +665,26 @@
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
+static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
+				      struct ieee80211_supported_band *sband,
+				      u64 *rates)
+{
+	int i, j, count;
+	*rates = 0;
+	count = 0;
+	for (i = 0; i < bss->supp_rates_len; i++) {
+		int rate = (bss->supp_rates[i] & 0x7F) * 5;
+
+		for (j = 0; j < sband->n_bitrates; j++)
+			if (sband->bitrates[j].bitrate == rate) {
+				*rates |= BIT(j);
+				count++;
+				break;
+			}
+	}
+
+	return count;
+}
 
 static void ieee80211_send_assoc(struct net_device *dev,
 				 struct ieee80211_if_sta *ifsta)
@@ -673,11 +693,12 @@
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, *ies;
-	int i, len;
+	int i, len, count, rates_len, supp_rates_len;
 	u16 capab;
 	struct ieee80211_sta_bss *bss;
 	int wmm = 0;
 	struct ieee80211_supported_band *sband;
+	u64 rates = 0;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -740,24 +761,39 @@
 	*pos++ = ifsta->ssid_len;
 	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-	len = sband->n_bitrates;
-	if (len > 8)
-		len = 8;
-	pos = skb_put(skb, len + 2);
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = len;
-	for (i = 0; i < len; i++) {
-		int rate = sband->bitrates[i].bitrate;
-		*pos++ = (u8) (rate / 5);
-	}
+	/* all supported rates should be added here but some APs
+	 * (e.g. D-Link DAP 1353 in b-only mode) don't like that
+	 * Therefore only add rates the AP supports */
+	rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+	supp_rates_len = rates_len;
+	if (supp_rates_len > 8)
+		supp_rates_len = 8;
 
-	if (sband->n_bitrates > len) {
-		pos = skb_put(skb, sband->n_bitrates - len + 2);
-		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = sband->n_bitrates - len;
-		for (i = len; i < sband->n_bitrates; i++) {
+	len = sband->n_bitrates;
+	pos = skb_put(skb, supp_rates_len + 2);
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = supp_rates_len;
+
+	count = 0;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		if (BIT(i) & rates) {
 			int rate = sband->bitrates[i].bitrate;
 			*pos++ = (u8) (rate / 5);
+			if (++count == 8)
+				break;
+		}
+	}
+
+	if (count == 8) {
+		pos = skb_put(skb, rates_len - count + 2);
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = rates_len - count;
+
+		for (i++; i < sband->n_bitrates; i++) {
+			if (BIT(i) & rates) {
+				int rate = sband->bitrates[i].bitrate;
+				*pos++ = (u8) (rate / 5);
+			}
 		}
 	}
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 02f436a..1958bfb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1305,11 +1305,11 @@
 		if (is_multicast_ether_addr(skb->data)) {
 			if (*mesh_ttl > 0) {
 				xmit_skb = skb_copy(skb, GFP_ATOMIC);
-				if (!xmit_skb && net_ratelimit())
+				if (xmit_skb)
+					xmit_skb->pkt_type = PACKET_OTHERHOST;
+				else if (net_ratelimit())
 					printk(KERN_DEBUG "%s: failed to clone "
 					       "multicast frame\n", dev->name);
-				else
-					xmit_skb->pkt_type = PACKET_OTHERHOST;
 			} else
 				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
 							     dropped_frames_ttl);
@@ -1395,7 +1395,7 @@
 		padding = ((4 - subframe_len) & 0x3);
 		/* the last MSDU has no padding */
 		if (subframe_len > remaining) {
-			printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
+			printk(KERN_DEBUG "%s: wrong buffer size\n", dev->name);
 			return RX_DROP_UNUSABLE;
 		}
 
@@ -1418,7 +1418,7 @@
 			eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
 							padding);
 			if (!eth) {
-				printk(KERN_DEBUG "%s: wrong buffer size ",
+				printk(KERN_DEBUG "%s: wrong buffer size\n",
 				       dev->name);
 				dev_kfree_skb(frame);
 				return RX_DROP_UNUSABLE;
@@ -1952,7 +1952,7 @@
 		if (!skb_new) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: failed to copy "
-				       "multicast frame for %s",
+				       "multicast frame for %s\n",
 				       wiphy_name(local->hw.wiphy),
 				       prev->dev->name);
 			continue;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index f35eaea..1d7dd54 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1562,13 +1562,13 @@
 	 * be cloned. This could happen, e.g., with Linux bridge code passing
 	 * us broadcast frames. */
 
-	if (head_need > 0 || skb_cloned(skb)) {
+	if (head_need > 0 || skb_header_cloned(skb)) {
 #if 0
 		printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
 		       "of headroom\n", dev->name, head_need);
 #endif
 
-		if (skb_cloned(skb))
+		if (skb_header_cloned(skb))
 			I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
 		else
 			I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -1898,6 +1898,7 @@
 			control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 		control->flags |= IEEE80211_TXCTL_NO_ACK;
+		control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
 		control->retry_limit = 1;
 		control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
 	}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index cc9f715..24a465c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -153,15 +153,15 @@
 	/* 7.1.3.5a.2 */
 	switch (ae) {
 	case 0:
-		return 5;
+		return 6;
 	case 1:
-		return 11;
+		return 12;
 	case 2:
-		return 17;
+		return 18;
 	case 3:
-		return 23;
+		return 24;
 	default:
-		return 5;
+		return 6;
 	}
 }
 
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 64faa3d..dc1598b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -394,7 +394,8 @@
 						 qd->handle);
 		if (!q->queues[i]) {
 			q->queues[i] = &noop_qdisc;
-			printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i);
+			printk(KERN_ERR "%s child qdisc %i creation failed\n",
+			       dev->name, i);
 		}
 	}
 
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 16774ec..0edefcf 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -472,6 +472,9 @@
 		goto nla_put_failure;
 	nla_nest_end(skb, nest_parms);
 
+	if (ctnetlink_dump_id(skb, ct) < 0)
+		goto nla_put_failure;
+
 	if (events & IPCT_DESTROY) {
 		if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
 		    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c
index 500528d..c63e933 100644
--- a/net/netfilter/xt_iprange.c
+++ b/net/netfilter/xt_iprange.c
@@ -179,3 +179,5 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>, Jan Engelhardt <jengelh@computergmbh.de>");
 MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching");
+MODULE_ALIAS("ipt_iprange");
+MODULE_ALIAS("ip6t_iprange");
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2507024..2cee87d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -743,7 +743,7 @@
 	if (len > dev->mtu+reserve)
 		goto out_unlock;
 
-	skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev),
+	skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
 				msg->msg_flags & MSG_DONTWAIT, &err);
 	if (skb==NULL)
 		goto out_unlock;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 81b6064..bbc7107 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2418,7 +2418,8 @@
 				break;
 
 			case SCTP_PARAM_IPV6_ADDRESS:
-				asoc->peer.ipv6_address = 1;
+				if (PF_INET6 == asoc->base.sk->sk_family)
+					asoc->peer.ipv6_address = 1;
 				break;
 
 			case SCTP_PARAM_HOST_NAME_ADDRESS:
@@ -2829,6 +2830,19 @@
 	addr_param = (union sctp_addr_param *)
 			((void *)asconf_param + sizeof(sctp_addip_param_t));
 
+	switch (addr_param->v4.param_hdr.type) {
+	case SCTP_PARAM_IPV6_ADDRESS:
+		if (!asoc->peer.ipv6_address)
+			return SCTP_ERROR_INV_PARAM;
+		break;
+	case SCTP_PARAM_IPV4_ADDRESS:
+		if (!asoc->peer.ipv4_address)
+			return SCTP_ERROR_INV_PARAM;
+		break;
+	default:
+		return SCTP_ERROR_INV_PARAM;
+	}
+
 	af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
 	if (unlikely(!af))
 		return SCTP_ERROR_INV_PARAM;
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 09cd9c0..3f964db 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -25,11 +25,11 @@
 	struct dst_entry *dst = skb->dst;
 	int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
 		- skb_headroom(skb);
+	int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
 
-	if (nhead > 0)
-		return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
+	if (nhead > 0 || ntail > 0)
+		return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
 
-	/* Check tail too... */
 	return 0;
 }
 
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 630684f..09b1661 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -539,8 +539,8 @@
 	{"HPRCOM", NULL, "Right HP Com"},
 
 	/* Mono Output */
-	{"MONOLOUT", NULL, "Mono Out"},
-	{"MONOLOUT", NULL, "Mono Out"},
+	{"MONO_LOUT", NULL, "Mono Out"},
+	{"MONO_LOUT", NULL, "Mono Out"},
 
 	/* Left Input */
 	{"Left Line1L Mux", "single-ended", "LINE1L"},
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index b2a11b0..f588545 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -416,7 +416,7 @@
 			 * to put data into its FIFO.  Without it, ALSA starts
 			 * to complain about overruns.
 			 */
-			msleep(1);
+			mdelay(1);
 		}
 		break;
 
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 83b1eb4..6533563 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -188,8 +188,8 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *jack_function[] = {"Off", "Headphone"};
 static const struct soc_enum n810_enum[] = {
-	SOC_ENUM_SINGLE_EXT(2, spk_function),
-	SOC_ENUM_SINGLE_EXT(3, jack_function),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
 };
 
 static const struct snd_kcontrol_new aic33_n810_controls[] = {
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index 478369b..b343818 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -341,8 +341,12 @@
 	case MIDI_CTL_SOFT_PEDAL:
 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
 		/* FIXME: this is an emulation */
-		snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, -160,
+		if (chan->control[type] >= 64)
+			snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, -160,
 				     EMUX_FX_FLAG_ADD);
+		else
+			snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, 0,
+				     EMUX_FX_FLAG_OFF);
 #endif
 		break;